]> git.saurik.com Git - wxWidgets.git/blame - utils/HelpGen/src/cjparser.cpp
don't let WM_RBUTTONDOWN reach def window proc as it would enter a local modal messag...
[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
8ad74db3 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
8ad74db3 164 if ( cur == _gSrcEnd ) return false;
d12e3536
VZ
165
166 if ( *cur == '/' )
167 {
168 if ( (*(cur+1) == '*') ||
8ad74db3 169 (*(cur+1) == '/') ) return true;
d12e3536
VZ
170 else
171 {
172 ++cur;
173 continue;
174 }
175 }
176
8ad74db3 177 return false;
d12e3536
VZ
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 )
8ad74db3 384 return false;
d12e3536 385 else
8ad74db3 386 return true;
cecfc5e7
VZ
387}
388
389static inline void skip_preprocessor_dir( char*& cur )
390{
d12e3536
VZ
391 do
392 {
393 skip_to_eol(cur);
cecfc5e7 394
d12e3536
VZ
395 if ( *(cur-1) != '\\' )
396 break;
cecfc5e7 397
d12e3536
VZ
398 if ( cur < _gSrcEnd )
399 skip_eol( cur );
400 else
401 break;
cecfc5e7 402
d12e3536 403 } while(1);
cecfc5e7
VZ
404}
405
406static void skip_token( char*& cur )
407{
d12e3536
VZ
408 if ( *cur == '"' )
409 {
410 skip_quoted_string( cur );
411 return;
412 }
413
414 if ( *cur == ',' ||
415 *cur == ';' ||
416 *cur == ')' ||
417 *cur == '('
418 )
419 {
420 ++cur;
421 return;
422 }
cecfc5e7 423
f71f5a4f
VZ
424 // special case of "!=", "<=", ... 2 character composite tokens
425 if ( *cur == '<' ||
d12e3536
VZ
426 *cur == '>' ||
427 *cur == '=' ||
f71f5a4f
VZ
428 *cur == '!'
429 )
430 {
431 cur++;
432 if ( *cur == '=' )
433 cur++;
434
435 return;
436 }
437
d12e3536
VZ
438 ++cur; // leading character is always skipped
439
440 for( ; cur < _gSrcEnd ; ++cur )
441 {
442 switch ( *cur )
443 {
444 case ' ' : break;
445 case '\t': break;
446 case 13 : break;
447 case 10 : break;
448 case ',' : break;
449 case ';' : break;
450 case '<' : break;
451 case '>' : break;
452
453 // FIXME:: QUICK-HACK:: to treat scope resolution
454 // tokens are a part of the string - e.g. SomeSpace::SubName would
455 // become one token
456
457 case ':' : if ( *(cur+1) == ':' )
458 {
459 ++cur;
460 continue;
461 }
462
463 break;
464 case '=' : break;
465 case '(' : break;
466 case ')' : break;
467 case '{' : break;
468 case '}' : break;
469
470 default : continue;
471 };
472 break;
473 }
cecfc5e7
VZ
474}
475
476static inline size_t get_token_len( char* tok )
477{
d12e3536 478 char* start = tok;
cecfc5e7 479
d12e3536 480 skip_token( tok );
cecfc5e7 481
d12e3536 482 return size_t( tok - start );
cecfc5e7
VZ
483}
484
485// returns true, if given tokens are equel
486
487static inline bool cmp_tokens( char* tok1, char* tok2 )
488{
d12e3536
VZ
489 // NOTE:: the case one token includes
490 // other in it's entirely is not handled
cecfc5e7 491
d12e3536 492 size_t len = get_token_len( tok1 );
cecfc5e7 493
d12e3536 494 // assuming that tokens are non-zero length
cecfc5e7 495
d12e3536
VZ
496 do
497 {
498 if ( *(tok1++) != *(tok2++) )
8ad74db3 499 return false;
cecfc5e7 500
d12e3536 501 --len;
cecfc5e7 502
d12e3536 503 } while ( --len );
cecfc5e7 504
8ad74db3 505 return true;
cecfc5e7
VZ
506}
507
508static inline bool cmp_tokens_fast( char* tok1, char* tok2, size_t len )
509{
d12e3536
VZ
510 do
511 {
512 if ( *(tok1++) != *(tok2++) )
8ad74db3 513 return false;
cecfc5e7 514
d12e3536 515 } while ( --len );
cecfc5e7 516
8ad74db3 517 return true;
cecfc5e7
VZ
518}
519
520static inline void skip_tempalate_statement( char*& cur )
521{
d12e3536 522 size_t level = 0;
cecfc5e7 523
d12e3536
VZ
524 // go one level deeper
525 while( *cur != '<' && cur < _gSrcEnd )
526 {
527 if (*cur == 10 ) ++_gLineNo;
528 ++cur;
529 }
cecfc5e7 530
d12e3536
VZ
531 // FIXME:: template should be checked statement for
532 // comments inside of it
cecfc5e7 533
d12e3536
VZ
534 do
535 {
536 if ( *cur == '<' )
537 ++level;
538 else
539 --level;
cecfc5e7 540
d12e3536 541 ++cur; // skip '<' or '>' token
cecfc5e7 542
d12e3536
VZ
543 if ( level == 0 )
544 return;
cecfc5e7 545
d12e3536
VZ
546 while( *cur != '<' && *cur != '>' && cur < _gSrcEnd )
547 {
548 if (*cur == 10 ) ++_gLineNo;
549 ++cur;
550 }
cecfc5e7 551
d12e3536 552 } while (1);
cecfc5e7
VZ
553}
554
555static inline void skip_statement( char*& cur )
556{
d12e3536 557 for( ; cur < _gSrcEnd; ++cur )
cecfc5e7 558
d12e3536
VZ
559 switch (*cur)
560 {
561 case ';' : ++cur; // skip statement-terminator token
562 return;
cecfc5e7 563
d12e3536
VZ
564 case '"' : skip_quoted_string(cur);
565 --cur;
566 continue;
cecfc5e7 567
d12e3536 568 case 10 : ++_gLineNo;
cecfc5e7 569
d12e3536
VZ
570 continue;
571 case '/' : skip_comments( cur );
572 --cur;
573 continue;
574 default : continue;
575 }
cecfc5e7
VZ
576}
577
578// "reversed" versions of skip_token() and get_next_token()
579
580static inline void skip_token_back( char*& cur )
581{
d12e3536
VZ
582 // FIXME:: now, when moving backwards, neither strings nor
583 // comment blocks are checked
cecfc5e7 584
d12e3536 585 --cur; // skip to the trailing character
cecfc5e7 586
d12e3536
VZ
587 if ( *cur == ',' ||
588 *cur == ')' ||
589 *cur == '('
590 )
591 return;
cecfc5e7
VZ
592
593
d12e3536
VZ
594 for( ; cur < _gSrcEnd ; --cur )
595 {
596 switch ( *cur )
597 {
598 case ' ' : break;
599 case '\t': break;
600 case 13 : break;
601 case 10 : break;
602 case ',' : break;
603 case '(' : break;
cecfc5e7 604
d12e3536
VZ
605 default : continue;
606 };
cecfc5e7 607
d12e3536
VZ
608 break;
609 }
cecfc5e7 610
d12e3536 611 ++cur; // get to the leading character of the token
cecfc5e7
VZ
612}
613
614static inline void skip_next_token_back( char*& cur )
615{
d12e3536
VZ
616 --cur; // skip leading character of the current token
617
618 if ( *cur == ',' ||
619 *cur == ')' ||
620 *cur == '('
621 )
622 {
623 ++cur;
624 return;
625 }
626
627 for( ; cur < _gSrcEnd; --cur )
628 {
629 switch ( *cur )
630 {
631 case ' ' : continue;
632 case '\t': continue;
633 case 13 : continue;
634 case 10 : continue;
635 case ',' : continue;
636 case '(' : continue;
637
638 default : break;
639 };
640
641 break;
642 }
643
644 ++cur; // position after the trailing charcter of the prev token
cecfc5e7
VZ
645}
646
647static string get_token_str( char* cur )
648{
d12e3536 649 return string( cur, get_token_len( cur ) );
cecfc5e7
VZ
650}
651
652// skips token or whole expression which may have
653// nested expressions between '(' ')' brackets.
654//
655// Upon return, the cursor points to the terminating bracket ')',
656//
657// Return value is the size of the block
658
659static size_t skip_block( char*& cur )
660{
d12e3536
VZ
661 size_t level = 0; // nesting level
662
663 char* start = cur;
664
665 // NOTE:: assumed that block not necessarely starts
666 // with bracket rightaway
667
668 if ( *cur == '(' )
669 {
670 ++level;
671 }
672
673 do
674 {
675 skip_token( cur );
676
677 char* savedPos = cur;
678 int tmpLnNo;
679 store_line_no( tmpLnNo );
680
681 get_next_token( cur );
682
683 if ( cur >= _gSrcEnd ) return 0;
684
685 if ( *cur == '(' )
686 {
687 ++level;
688 }
689 else
690 if ( *cur == ')' )
691 {
692 if ( level == 0 )
693 {
694 cur = savedPos;
695 restore_line_no( tmpLnNo );
696
697 return size_t(cur-start);
698 }
699
700 --level;
701
702 if ( level == 0 )
703 {
704 ++cur;
705
706 // QUICK-HACK::to easily handle function prototypes ,
707 // it works, besause theoretically there should
708 // be no cast-expressions in non-implementation
709 // scope (e.g. "time( (long*)(ptr+1) )" should not
710 // appear in the declarations, thus it is most likelly
711 // for the ")(" fragment to be within a function
712 // prototype in the declarations scope
713
714 if ( *cur == '(' )
715 {
716 ++level;
717 continue;
718 }
719
720 else return size_t(cur-start);
721 }
722 }
723 else
724 {
725 if ( level == 0 )
726 {
727 cur = savedPos;
728 restore_line_no( tmpLnNo );
729
730 return size_t(cur-start);
731 }
732 }
733
734 } while(1);
cecfc5e7
VZ
735}
736
737// returns 0, if end of source reached
738static inline bool skip_imp_block( char*& cur )
739{
d12e3536
VZ
740 while( *cur != '{' && cur < _gSrcEnd )
741 {
742 skip_token( cur );
8ad74db3 743 if ( !get_next_token( cur ) ) return false;
d12e3536 744 }
cecfc5e7 745
d12e3536
VZ
746 while( *cur != '}' && cur < _gSrcEnd )
747 {
748 skip_token( cur );
8ad74db3 749 if ( !get_next_token( cur ) ) return false;
d12e3536 750 }
cecfc5e7 751
d12e3536 752 ++cur;
cecfc5e7 753
8ad74db3 754 return true;
cecfc5e7
VZ
755}
756
757static bool is_class_token( char*& cur )
758{
d12e3536 759 // FIXME:: the below mess should be cleaned in it's entirely
cecfc5e7 760
d12e3536
VZ
761 if ( *cur == 'i' )
762 if ( *(cur+1) == 'n' )
cecfc5e7 763
d12e3536 764 return cmp_tokens_fast( cur, "interface", 9 );
cecfc5e7 765
d12e3536
VZ
766 if ( *cur == 'c' )
767 if ( *(cur+1) == 'l' )
cecfc5e7 768
d12e3536 769 return cmp_tokens_fast( cur, "class", 5 );
cecfc5e7 770
d12e3536
VZ
771 if ( *cur == 's' )
772 if ( *(cur+1) == 't' )
cecfc5e7 773
d12e3536 774 return cmp_tokens_fast( cur, "struct", 6 );
cecfc5e7 775
d12e3536
VZ
776 if ( *cur == 'u' )
777 if ( *(cur+1) == 'n' )
cecfc5e7 778
d12e3536 779 return cmp_tokens_fast( cur, "union", 5 );
cecfc5e7 780
8ad74db3 781 return false;
cecfc5e7
VZ
782}
783
784inline static bool is_forward_decl( char* cur )
785{
d12e3536
VZ
786 do
787 {
788 switch( *cur )
789 {
8ad74db3
WS
790 case ':' : return false;
791 case '{' : return false;
792 case '(' : return false;
cecfc5e7 793
8ad74db3 794 case ';' : return true;
cecfc5e7 795
d12e3536
VZ
796 default : break;
797 };
cecfc5e7 798
d12e3536 799 ++cur;
cecfc5e7 800
d12e3536 801 } while (cur < _gSrcEnd); // prevent running out of bounds
cecfc5e7 802
8ad74db3 803 return false;
cecfc5e7
VZ
804}
805
806inline static bool is_function( char* cur, bool& isAMacro )
807{
8ad74db3 808 isAMacro = false;
cecfc5e7 809
d12e3536
VZ
810 int tmpLnNo;
811 store_line_no( tmpLnNo );
cecfc5e7 812
d12e3536 813 // NOTE:: comments and quoted strings are not checked here
cecfc5e7 814
d12e3536
VZ
815 // first,check for "single-line hanginging macros" like:
816 // ___UNICODE
817 //
cecfc5e7 818
d12e3536
VZ
819 char* eol = cur;
820 skip_to_eol( eol );
cecfc5e7 821
d12e3536
VZ
822 skip_token( cur );
823 get_next_token( cur );
cecfc5e7 824
d12e3536
VZ
825 if ( cur > eol )
826 {
8ad74db3 827 isAMacro = true;
d12e3536 828 restore_line_no( tmpLnNo );
cecfc5e7 829
8ad74db3 830 return true;
d12e3536 831 }
cecfc5e7 832
d12e3536 833 // it's not a macro, go to the begining of arg. list
cecfc5e7 834
d12e3536
VZ
835 do
836 {
837 // if bracket found, it's a function or a begining
838 // of some macro
839 if ( *cur == '(' )
840 {
841 restore_line_no( tmpLnNo );
8ad74db3 842 return true;
d12e3536 843 }
cecfc5e7 844
d12e3536
VZ
845 // end of statement found without any brackets in it
846 // - it cannot be a function
cecfc5e7 847
d12e3536
VZ
848 if ( *cur == ';' )
849 {
850 restore_line_no( tmpLnNo );
8ad74db3 851 return false;
d12e3536 852 }
cecfc5e7 853
d12e3536 854 ++cur;
cecfc5e7 855
d12e3536 856 } while( cur < _gSrcEnd);
cecfc5e7 857
d12e3536
VZ
858 isAMacro = 1;
859 restore_line_no( tmpLnNo );
860
8ad74db3 861 return false;
cecfc5e7
VZ
862}
863
864// upon return the cursor is positioned after the
d12e3536 865// terminating curly brace
cecfc5e7
VZ
866
867static inline void skip_scope_block( char*& cur )
868{
d12e3536 869 size_t level = 0;
cecfc5e7 870
d12e3536 871 for( ; cur < _gSrcEnd ; ++cur )
cecfc5e7 872
d12e3536
VZ
873 switch( *cur )
874 {
875 case '/' : skip_comments( cur );
876 --cur;
877 continue;
878 case '"' : skip_quoted_string( cur );
879 --cur;
880 continue;
881
882 case '{' : ++level;
883 continue;
884
885 case '}' :--level;
886 if ( level == 0 )
887 {
888 ++cur; // skip final closing curly brace
889 return;
890 }
891
892 case 10 : ++_gLineNo; continue;
893
894 default : continue;
895 };
cecfc5e7
VZ
896}
897
898// moves tokens like '*' '**', '***', '&' from the name
899// to the type
900
901static void arrange_indirection_tokens_between( string& type,
d12e3536 902 string& identifier )
cecfc5e7 903{
d12e3536 904 // TBD:: FIXME:: return value of operators !
cecfc5e7 905
753287c1
MB
906 while ( identifier[0u] == '*' ||
907 identifier[0u] == '&'
d12e3536
VZ
908 )
909 {
753287c1 910 type += identifier[0u];
d12e3536 911 identifier.erase(0,1);
cecfc5e7 912
d12e3536
VZ
913 if ( !identifier.length() ) return;
914 }
cecfc5e7
VZ
915}
916
917
918// the only function where multi-lang keyword map is accessed
919
920static bool is_keyword( char* cur )
921{
d12e3536
VZ
922 size_t len = get_token_len( cur );
923
924 // put a terminating zero after the given token
925 char tmp = *(cur + len);
926 *(cur+len) = '\0';
cecfc5e7 927
d12e3536 928 KeywordMapT::iterator i;
cecfc5e7 929
d12e3536
VZ
930 i = __gMultiLangMap.find( cur );
931
932 // restore original character suppresed by terminating zero
933 *(cur + len) = tmp;
cecfc5e7 934
59734eb5 935 return i == __gMultiLangMap.end() ? false : true;
cecfc5e7
VZ
936}
937
d12e3536
VZ
938static inline void get_string_between( char* start, char* end,
939 string* pStr )
cecfc5e7 940{
d12e3536 941 char saved = *end;
cecfc5e7 942
d12e3536
VZ
943 *end = '\0';
944 *pStr = start;
945 *end = saved;
cecfc5e7
VZ
946}
947
948static char* set_comment_text( string& text, char* start )
949{
d12e3536 950 char* end = start;
cecfc5e7 951
d12e3536
VZ
952 // to avoid poluting the queue with this comment
953 _gLastSuppresedComment = start;
cecfc5e7 954
d12e3536 955 skip_comments( end );
cecfc5e7 956
d12e3536
VZ
957 if ( *(end-1) == '/' )
958 end -= 2;
cecfc5e7 959
d12e3536 960 start += 2;
cecfc5e7 961
d12e3536
VZ
962 // skip multiple leading '/''s or '*''s
963 while( *start == '/' && start < end ) ++start;
964 while( *start == '*' && start < end ) ++start;
cecfc5e7 965
d12e3536 966 get_string_between( start, end, &text );
cecfc5e7 967
d12e3536 968 return end;
cecfc5e7
VZ
969}
970
971/***** Implementation for class CJSourceParser *****/
972
973CJSourceParser::CJSourceParser( bool collectCommnets, bool collectMacros )
d12e3536
VZ
974 : mpStart(0),
975 mpEnd(0),
976 mpCurCtx( 0 ),
977 mCommentsOn( collectCommnets ),
978 mMacrosOn ( collectMacros )
cecfc5e7 979{
d12e3536 980 check_keyword_map();
cecfc5e7
VZ
981}
982
983spFile* CJSourceParser::Parse( char* start, char* end )
984{
d12e3536
VZ
985 // set up state variables
986 mCurVis = SP_VIS_PRIVATE;
987
988 spFile* pTopCtx = new spFile();
989 mpCurCtx = pTopCtx;
990
991 mIsVirtual = 0;
992 mIsTemplate = 0;
993 mNestingLevel = 0;
994
995 cur = start;
996
997 mpStart = start;
998 mpEnd = end;
999
1000 _gSrcEnd = mpEnd; // let all the C-functions "smell" the end of file
1001 _gSrcStart = start;
1002
1003 _gLineNo = 0;
1004
1005 clear_commets_queue();
1006
1007 // main parsing loop
1008
1009 do
1010 {
1011 if ( !get_next_token( cur ) )
1012 // end of source reached
1013 return pTopCtx;
1014
1015 if ( memcmp( cur, "ScriptSection( const string&",
1016 strlen( "ScriptSection( const string&" )
1017 ) == 0
1018 )
1019 {
8ad74db3
WS
1020 // int o = 0;
1021 // ++o;
d12e3536
VZ
1022 }
1023
1024 switch (*cur)
1025 {
1026 case '#' :
1027 {
1028 AddMacroNode( cur );
1029 continue;
1030 }
1031
1032 case ':' :
1033 {
1034 skip_token( cur );
1035 continue;
1036 }
1037
1038 case ';' :
1039 {
1040 skip_token( cur );
1041 continue;
1042 }
1043
1044 case ')' :
1045 {
1046 skip_token( cur );
1047 continue;
1048 }
1049
1050 case '=' :
1051 {
1052 skip_token( cur );
1053 continue;
1054 }
1055
1056 default: break;
1057 }
cecfc5e7 1058
59734eb5 1059 // 'const' is a part of the return type, not a keyword here
d12e3536
VZ
1060 if ( strncmp(cur, "const", 5) != 0 && is_keyword( cur ) )
1061 {
1062 // parses, token, if token identifies
1063 // the container context (e.g. class/namespace)
1064 // the corresponding context object is created
1065 // and set as current context
cecfc5e7 1066
d12e3536
VZ
1067 ParseKeyword( cur );
1068 continue;
1069 }
cecfc5e7 1070
d12e3536
VZ
1071 if ( *cur >= '0' && *cur <= '9' )
1072 {
1073 skip_token( cur );
1074 continue;
1075 }
cecfc5e7 1076
d12e3536
VZ
1077 if ( *cur == '}' )
1078 {
1079 if ( mCurCtxType != SP_CTX_CLASS )
1080 {
1081 // FOR NOW:: disable the below assertion
cecfc5e7 1082
d12e3536
VZ
1083 // DBG:: unexpected closing-bracket found
1084 //ASSERT(0);
cecfc5e7 1085
d12e3536
VZ
1086 skip_token( cur ); // just skip it
1087 continue;
1088 }
cecfc5e7 1089
d12e3536
VZ
1090 if ( mpCurCtx->GetType() == SP_CTX_CLASS )
1091 {
1092 int curOfs = ( (cur+1) - _gSrcStart );
cecfc5e7 1093
d12e3536
VZ
1094 mpCurCtx->mContextLength = ( curOfs - mpCurCtx->mSrcOffset );
1095 }
1096
1097 --mNestingLevel;
cecfc5e7 1098
d12e3536
VZ
1099 // terminate operation/class/namespace context
1100 // TBD:: check if it's really this type of context
cecfc5e7 1101
d12e3536
VZ
1102 wxASSERT( mpCurCtx );
1103 mpCurCtx = mpCurCtx->GetOutterContext();
1104 wxASSERT( mpCurCtx );
cecfc5e7 1105
d12e3536
VZ
1106 if ( mNestingLevel == 0 )
1107 {
cecfc5e7 1108
d12e3536 1109 mCurCtxType = SP_CTX_FILE;
cecfc5e7 1110
d12e3536
VZ
1111 // not-nested class delclaration finished,
1112 // rest template flag in any case
1113 mIsTemplate = 0;
1114 }
cecfc5e7 1115
d12e3536
VZ
1116 skip_token( cur );
1117 continue;
1118 }
cecfc5e7 1119
8ad74db3 1120 bool isAMacro = false;
cecfc5e7 1121
d12e3536
VZ
1122 if ( is_function( cur, isAMacro ) )
1123 {
1124 if ( isAMacro )
1125 {
1126 skip_token( cur );
1127 continue;
1128 }
cecfc5e7 1129
d12e3536 1130 char* savedPos = cur;
cecfc5e7 1131
d12e3536
VZ
1132 int tmpLnNo;
1133 store_line_no( tmpLnNo );
8ad74db3 1134 wxUnusedVar( tmpLnNo );
cecfc5e7 1135
8ad74db3 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
8ad74db3 1222 pComment->mStartsPar = true;
d12e3536
VZ
1223 else
1224 if ( pComment->mIsMultiline )
cecfc5e7 1225
8ad74db3 1226 pComment->mStartsPar = true;
d12e3536
VZ
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
8ad74db3 1238 pComment->mStartsPar = true;
d12e3536 1239 else
8ad74db3 1240 pComment->mStartsPar = false;
d12e3536 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{
8ad74db3 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 1539 skip_token( cur );
8ad74db3 1540 if ( !get_next_token( cur ) ) return false;
d12e3536 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
8ad74db3 1567 isAMacro = true;
cecfc5e7 1568
8ad74db3 1569 return false;
d12e3536
VZ
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
8ad74db3 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
8ad74db3 1658 bool first_blk = true;
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
8ad74db3 1696 return false;
d12e3536 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
8ad74db3
WS
1780 bool result = true;
1781
d12e3536
VZ
1782 do
1783 {
1784 if ( *tok == '{' || *tok == ';' )
1785 {
1786 restore_line_no(tmpLnNo);
8ad74db3 1787 break;
d12e3536
VZ
1788 }
1789
1790 // check for unexpected tokens
1791 if ( *tok == '=' || *tok == '0' )
1792 {
1793 skip_token(tok);
8ad74db3 1794 if ( !get_next_token(tok) ) return false;
d12e3536
VZ
1795 continue;
1796 }
1797
8ad74db3 1798 if ( *tok == '}' ) return false;
d12e3536
VZ
1799
1800 // if initialization list found
1801 if ( *tok == ':' )
1802 {
1803 restore_line_no(tmpLnNo);
8ad74db3 1804 break;
d12e3536
VZ
1805 }
1806
1807 if ( cmp_tokens_fast( tok, "const", 5 ) )
1808 {
59734eb5
VZ
1809 ((spOperation*)mpCurCtx)->mIsConstant = true;
1810
d12e3536 1811 skip_token(tok);
8ad74db3 1812 if ( !get_next_token(tok) ) return false;
d12e3536
VZ
1813 continue;
1814 }
1815
8ad74db3 1816 if ( CheckVisibilty( tok ) ) return false;
cecfc5e7 1817
d12e3536 1818 // if next context found
8ad74db3 1819 if ( is_keyword( tok ) ) return false;
cecfc5e7 1820
d12e3536 1821 skip_token(tok);
8ad74db3 1822 if ( !get_next_token(tok) ) return false;
cecfc5e7 1823
d12e3536 1824 } while(1);
cecfc5e7 1825
8ad74db3 1826 return result;
cecfc5e7
VZ
1827}
1828
1829void CJSourceParser::ParseMemberVar( char*& cur )
1830{
d12e3536 1831 MMemberListT& members = mpCurCtx->GetMembers();
cecfc5e7 1832
8ad74db3 1833 bool firstMember = true;
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;
d12e3536 1863 }
cecfc5e7 1864
d12e3536 1865 skip_token_back( cur );
cecfc5e7 1866
d12e3536
VZ
1867 // attach comments about the attribute
1868 AttachComments( *pAttr, cur );
cecfc5e7 1869
d12e3536 1870 pAttr->mName = get_token_str( cur );
cecfc5e7 1871
d12e3536
VZ
1872 // guessing that this going to be variable type
1873 skip_next_token_back( cur );
1874 skip_token_back( cur );
1875
1876 pAttr->mType = get_token_str( cur );
cecfc5e7 1877
d12e3536
VZ
1878 // if comma, than variable list continues
1879 // otherwise the variable type reached - stop
cecfc5e7 1880
d12e3536
VZ
1881 if ( *cur == '=' )
1882 {
1883 // yes, we've mistaken, it was not a identifier,
1884 // but it's default value
1885 pAttr->mInitVal =
1886 pAttr->mName;
cecfc5e7 1887
d12e3536
VZ
1888 // skip default value and '=' symbol
1889 skip_next_token_back( cur );
1890 skip_token_back( cur );
cecfc5e7 1891
d12e3536 1892 pAttr->mName = get_token_str( cur );
cecfc5e7 1893
d12e3536
VZ
1894 skip_next_token_back( cur );
1895 skip_token_back( cur );
1896 }
cecfc5e7 1897
d12e3536
VZ
1898 if ( *cur != ',' )
1899 {
1900 type = get_token_str( cur );
1901 break;
1902 }
cecfc5e7 1903
d12e3536 1904 } while(1);
cecfc5e7 1905
8ad74db3 1906 size_t first = 0;
cecfc5e7 1907
d12e3536
VZ
1908 // set up types for all collected (same-type) attributes;
1909 while ( first != members.size() - 1 )
1910 {
1911 spAttribute* pAttr = members[first++]->CastToAttribute();
1912 if ( !pAttr )
1913 continue;
cecfc5e7 1914
d12e3536
VZ
1915 if ( !pAttr->mType )
1916 pAttr->mType = type;
1917 pAttr->mVisibility = mCurVis;
cecfc5e7 1918
d12e3536
VZ
1919 if ( !!pAttr->mName )
1920 arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
1921 }
cecfc5e7 1922
d12e3536
VZ
1923 cur = savedPos;
1924 restore_line_no( tmpLnNo );
cecfc5e7 1925
d12e3536 1926 clear_commets_queue();
cecfc5e7
VZ
1927
1928
1929}
1930
1931void CJSourceParser::SkipFunction( char*& cur )
1932{
d12e3536
VZ
1933 while ( *cur != '(' && cur < _gSrcEnd )
1934 {
1935 if (*cur == 10 ) ++_gLineNo;
1936 ++cur;
1937 }
cecfc5e7 1938
d12e3536
VZ
1939 skip_next_token_back( cur ); // go back and skip function identifier
1940 skip_token_back( cur ); // go back and skip return type
cecfc5e7 1941
d12e3536 1942 skip_block( cur ); // now, go ahead and skip whole declaration
cecfc5e7 1943
d12e3536 1944 SkipFunctionBody( cur );
cecfc5e7
VZ
1945
1946}
1947
1948void CJSourceParser::SkipFunctionBody( char*& cur )
1949{
d12e3536 1950 // FIXME:: check for comments and quoted stirngs here
cecfc5e7 1951
8ad74db3 1952 bool hasDefinition = false;
cecfc5e7 1953
d12e3536
VZ
1954 while( *cur != '{' && *cur != ';' )
1955 {
1956 if (*cur == 10 ) ++_gLineNo;
1957 ++cur;
1958 }
cecfc5e7 1959
d12e3536
VZ
1960 if ( *cur == ';' )
1961 {
1962 ++cur;
1963 }
1964 else
1965 {
8ad74db3 1966 hasDefinition = true;
cecfc5e7 1967
d12e3536
VZ
1968 skip_scope_block( cur ); // skip the whole imp.
1969 }
cecfc5e7 1970
d12e3536
VZ
1971 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1972 {
1973 spOperation& op = *((spOperation*)mpCurCtx);
cecfc5e7 1974
d12e3536 1975 int curOfs = int ( cur - _gSrcStart );
cecfc5e7 1976
d12e3536 1977 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
cecfc5e7 1978
d12e3536 1979 op.mHasDefinition = hasDefinition;
cecfc5e7 1980
d12e3536 1981 // separate scope resolution token from the name of operation
cecfc5e7 1982
d12e3536
VZ
1983 for( size_t i = 0; i != op.mName.length(); ++i )
1984 {
1985 if ( op.mName[i] == ':' && op.mName[i+1] == ':' )
1986 {
1987 string unscoped( op.mName, i+2, op.mName.length() - ( i + 2 ) );
cecfc5e7 1988
d12e3536 1989 op.mScope = string( op.mName, 0, i );
cecfc5e7 1990
d12e3536 1991 op.mName = unscoped;
cecfc5e7 1992
d12e3536
VZ
1993 break;
1994 }
1995 }
1996 }
cecfc5e7
VZ
1997}
1998
1999bool CJSourceParser::CheckVisibilty( char*& cur )
2000{
d12e3536
VZ
2001 size_t len = get_token_len( cur );
2002
2003 if ( cmp_tokens_fast( cur, "public:", len ) )
2004 {
2005 mCurVis = SP_VIS_PUBLIC;
8ad74db3 2006 return true;
d12e3536
VZ
2007 }
2008
2009 if ( cmp_tokens_fast( cur, "protected:", len ) )
2010 {
2011 mCurVis = SP_VIS_PROTECTED;
8ad74db3 2012 return true;
d12e3536
VZ
2013 }
2014
2015 if ( cmp_tokens_fast( cur, "private:", len ) )
2016 {
2017 mCurVis = SP_VIS_PRIVATE;
8ad74db3 2018 return true;
d12e3536
VZ
2019 }
2020
8ad74db3 2021 return false;
cecfc5e7
VZ
2022}
2023
2024void CJSourceParser::AddClassNode( char*& cur )
2025{
d12e3536
VZ
2026 char* ctxStart = cur;
2027
2028 string classkeyword = get_token_str( cur );
2029
2030 skip_token( cur ); // skip 'class' keyword
2031 if ( !get_next_token( cur ) ) return;
2032
2033 // in C++
2034 if ( *cur == ':' )
2035 {
2036 skip_token( cur );
2037 get_next_token( cur );
2038 }
cecfc5e7 2039
d12e3536
VZ
2040 // by default all class members are private
2041 mCurVis = SP_VIS_PRIVATE;
cecfc5e7 2042
d12e3536
VZ
2043 spClass* pClass = new spClass();
2044 if ( classkeyword == "class" )
2045 pClass->mClassSubType = SP_CLTYPE_CLASS;
2046 else if ( classkeyword == "struct" ) {
2047 pClass->mClassSubType = SP_CLTYPE_STRUCTURE;
cecfc5e7 2048
d12e3536
VZ
2049 mCurVis = SP_VIS_PUBLIC;
2050 }
2051 else if ( classkeyword == "union" ) {
2052 pClass->mClassSubType = SP_CLTYPE_UNION;
cecfc5e7 2053
d12e3536
VZ
2054 mCurVis = SP_VIS_PUBLIC;
2055 }
2056 else if ( classkeyword == "interface" )
2057 pClass->mClassSubType = SP_CLTYPE_INTERFACE;
2058 else {
2059 pClass->mClassSubType = SP_CLTYPE_INVALID;
cecfc5e7 2060
d12e3536
VZ
2061 wxFAIL_MSG("unknown class keyword");
2062 }
cecfc5e7 2063
d12e3536 2064 mpCurCtx->AddMember( pClass );
cecfc5e7 2065
d12e3536
VZ
2066 // attach comments about the class
2067 AttachComments( *pClass, cur );
cecfc5e7 2068
d12e3536 2069 pClass->mSrcLineNo = get_line_no();
cecfc5e7 2070
d12e3536 2071 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
cecfc5e7 2072
d12e3536
VZ
2073 char* nameTok = cur;
2074 pClass->mName = get_token_str( cur );
cecfc5e7 2075
d12e3536 2076 bool isDerived = 0;
cecfc5e7 2077
d12e3536 2078 // DANGER-MACROS::
cecfc5e7 2079
d12e3536
VZ
2080 do
2081 {
2082 skip_token( cur );
2083 if ( !get_next_token( cur ) ) return;
cecfc5e7 2084
d12e3536
VZ
2085 if ( *cur == ':' )
2086 {
2087 isDerived = 1;
cecfc5e7 2088
d12e3536 2089 char* tok = cur;
cecfc5e7 2090
d12e3536
VZ
2091 int tmpLn;
2092 store_line_no( tmpLn );
cecfc5e7 2093
d12e3536
VZ
2094 skip_next_token_back( tok );
2095 skip_token_back( tok );
cecfc5e7 2096
d12e3536 2097 restore_line_no( tmpLn );
cecfc5e7 2098
d12e3536
VZ
2099 // class name should precend ':' colon, thus
2100 // the one which was captured before was
2101 // proablty something else (like __dllexport MyClass : ... )
cecfc5e7 2102
d12e3536
VZ
2103 if ( nameTok != tok )
2104 {
2105 pClass->mName = get_token_str( tok );
2106 }
cecfc5e7 2107
d12e3536 2108 }
cecfc5e7 2109
d12e3536
VZ
2110 if ( *cur == '{' )
2111 break;
cecfc5e7 2112
d12e3536
VZ
2113 if ( *cur == ',' )
2114 continue;
cecfc5e7 2115
d12e3536 2116 size_t len = get_token_len( cur );
cecfc5e7 2117
d12e3536
VZ
2118 // skip neglectable C++ modifieres
2119 if ( cmp_tokens_fast( cur, "public", len ) )
2120 continue;
cecfc5e7 2121
d12e3536
VZ
2122 if ( cmp_tokens_fast( cur, "protected", len ) )
2123 continue;
cecfc5e7 2124
d12e3536
VZ
2125 if ( cmp_tokens_fast( cur, "private", len ) )
2126 continue;
cecfc5e7 2127
d12e3536
VZ
2128 if ( cmp_tokens_fast( cur, "virtual", len ) )
2129 continue;
cecfc5e7 2130
d12e3536 2131 // skip neglectable JAVA modifieres
cecfc5e7 2132
d12e3536
VZ
2133 if ( cmp_tokens_fast( cur, "extends", len ) )
2134 {
2135 isDerived = 1;
2136 continue;
2137 }
cecfc5e7 2138
d12e3536
VZ
2139 if ( cmp_tokens_fast( cur, "implements", len ) )
2140 {
2141 isDerived = 1;
2142 continue;
2143 }
cecfc5e7 2144
d12e3536 2145 // all we need to know is superclass or interface
cecfc5e7 2146
d12e3536
VZ
2147 char* tok = cur;
2148 int tmpLn;
2149 store_line_no( tmpLn );
cecfc5e7 2150
d12e3536
VZ
2151 skip_token(tok);
2152 get_next_token(tok);
cecfc5e7 2153
d12e3536 2154 restore_line_no( tmpLn );
cecfc5e7 2155
d12e3536 2156 if ( *tok != ':' && *cur != ':' )
cecfc5e7 2157
d12e3536 2158 pClass->mSuperClassNames.push_back( string( cur, len ) );
cecfc5e7 2159
d12e3536 2160 } while(1);
cecfc5e7 2161
d12e3536
VZ
2162 if ( !isDerived )
2163 {
2164 int tmpLn;
2165 store_line_no( tmpLn );
2166
2167 while ( pClass->mSuperClassNames.size() )
2168
2169 pClass->mSuperClassNames.erase( &pClass->mSuperClassNames[0] );
cecfc5e7 2170
d12e3536 2171 char* tok = cur;
cecfc5e7 2172
d12e3536
VZ
2173 // some non-obviouse token was following "class" keyword -
2174 // we've confused it with class name - thus now we're reverting this mistake
cecfc5e7 2175
d12e3536
VZ
2176 skip_next_token_back( tok );
2177 skip_token_back( tok );
cecfc5e7 2178
d12e3536 2179 pClass->mName = get_token_str( tok );
cecfc5e7 2180
d12e3536
VZ
2181 restore_line_no( tmpLn );
2182 }
cecfc5e7
VZ
2183
2184
d12e3536 2185 ++cur; // skip opening curly brace
cecfc5e7 2186
d12e3536 2187 pClass->mHeaderLength = ( cur - ctxStart );
cecfc5e7 2188
d12e3536
VZ
2189 // now, enter the class context
2190 mpCurCtx = pClass;
cecfc5e7 2191
d12e3536 2192 clear_commets_queue();
cecfc5e7
VZ
2193}
2194
2195void CJSourceParser::AddEnumNode( char*& cur )
2196{
d12e3536
VZ
2197 // now the cursor is at "enum" keyword
2198 char* start = cur;
2199
2200 spEnumeration* pEnum = new spEnumeration();
2201 mpCurCtx->AddMember( pEnum );
cecfc5e7 2202
d12e3536 2203 pEnum->mSrcLineNo = get_line_no();
cecfc5e7 2204
cecfc5e7 2205
d12e3536 2206 AttachComments( *pEnum, cur );
cecfc5e7 2207
d12e3536
VZ
2208 skip_token( cur );
2209 if ( !get_next_token( cur ) ) return;
cecfc5e7 2210
d12e3536
VZ
2211 // check if enumeration has got it's identifier
2212 if ( *cur != '{' )
2213 {
2214 pEnum->mName = get_token_str( cur );
2215 }
cecfc5e7 2216
d12e3536 2217 if ( !skip_imp_block( cur ) ) return;
cecfc5e7 2218
d12e3536 2219 get_string_between( start, cur, &pEnum->mEnumContent );
cecfc5e7 2220
d12e3536
VZ
2221 if ( get_next_token(cur) )
2222 {
2223 // check if the identifier if after the {...} block
2224 if ( *cur != ';' )
cecfc5e7 2225
d12e3536
VZ
2226 pEnum->mName = get_token_str( cur );
2227 }
cecfc5e7 2228
d12e3536 2229 clear_commets_queue();
cecfc5e7
VZ
2230}
2231
2232void CJSourceParser::AddTypeDefNode( char*& cur )
2233{
d12e3536 2234 // now the cursor at the token next to "typedef" keyword
cecfc5e7 2235
d12e3536 2236 if ( !get_next_token(cur) ) return;
cecfc5e7 2237
d12e3536 2238 char* start = cur;
cecfc5e7 2239
d12e3536
VZ
2240 spTypeDef* pTDef = new spTypeDef();
2241 mpCurCtx->AddMember( pTDef );
cecfc5e7 2242
d12e3536 2243 pTDef->mSrcLineNo = get_line_no();
cecfc5e7 2244
d12e3536 2245 AttachComments( *pTDef, cur );
cecfc5e7 2246
d12e3536 2247 skip_statement( cur );
cecfc5e7 2248
d12e3536
VZ
2249 int tmpLnNo;
2250 store_line_no( tmpLnNo );
cecfc5e7 2251
d12e3536
VZ
2252 char* tok = cur-1;
2253 skip_next_token_back( tok );
cecfc5e7 2254
d12e3536 2255 char* nameEnd = tok;
cecfc5e7 2256
d12e3536 2257 skip_token_back( tok );
cecfc5e7 2258
d12e3536 2259 char* nameStart = tok;
cecfc5e7 2260
d12e3536 2261 skip_next_token_back( tok );
cecfc5e7 2262
d12e3536 2263 char* typeEnd = tok;
cecfc5e7 2264
d12e3536
VZ
2265 // check if it's function prototype
2266 if ( *nameStart == ')' )
2267 {
2268 typeEnd = nameStart+1;
2269
2270 // skip argument list
2271 while ( *nameStart != '(' ) --nameStart;
cecfc5e7 2272
d12e3536
VZ
2273 // skip to function type definition
2274 while ( *nameStart != ')' ) --nameStart;
cecfc5e7 2275
d12e3536 2276 skip_next_token_back( nameStart );
cecfc5e7 2277
d12e3536 2278 nameEnd = nameStart;
cecfc5e7 2279
d12e3536 2280 skip_token_back( nameStart );
cecfc5e7 2281
d12e3536
VZ
2282 if ( *nameStart == '*' ) ++nameStart;
2283 }
cecfc5e7 2284
d12e3536 2285 get_string_between( start, typeEnd, &pTDef->mOriginalType );
cecfc5e7 2286
d12e3536 2287 get_string_between( nameStart, nameEnd, &pTDef->mName );
cecfc5e7 2288
d12e3536 2289 clear_commets_queue();
cecfc5e7 2290
d12e3536 2291 restore_line_no( tmpLnNo );
cecfc5e7 2292}