]> git.saurik.com Git - wxWidgets.git/blame - utils/HelpGen/src/cjparser.cpp
wxCocoa build fix. Use XPM everywhere.
[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
8bc17f14 1307 pPL->m_Name = 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 )
8bc17f14 1579 pOp->mScope = mpCurCtx->m_Name;
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
8bc17f14 1591 pOp->m_Name = get_token_str( cur );
cecfc5e7 1592
f71f5a4f 1593 // checker whether it's not an operator
8bc17f14 1594 char chFirst = *pOp->m_Name.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" ) {
8bc17f14
WS
1602 lastToken += pOp->m_Name;
1603 pOp->m_Name = lastToken;
f71f5a4f 1604 }
d12e3536 1605 else {
f71f5a4f
VZ
1606 // ok, it wasn't an operator after all
1607 skip_token( cur );
1608 }
1609 }
8bc17f14 1610 else if ( pOp->m_Name == "operator" ) {
d12e3536
VZ
1611 skip_token( cur );
1612 get_next_token( cur );
1613 string oper = get_token_str( cur );
f71f5a4f 1614
8bc17f14 1615 pOp->m_Name += oper;
d12e3536 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 ) );
42389ac7 1624 // FIXME just for now...
8bc17f14 1625 string::size_type pos = 0;
42389ac7
MW
1626 string toerase("WXDLLEXPORT ");
1627 while((pos = rettype.find(toerase, pos)) != string::npos)
1628 rettype.erase(pos, toerase.length());
d12e3536
VZ
1629 pOp->mRetType = rettype;
1630 }
cecfc5e7 1631
8bc17f14 1632 arrange_indirection_tokens_between( pOp->mRetType, pOp->m_Name );
cecfc5e7 1633
d12e3536
VZ
1634 cur = savedPos;
1635 restore_line_no( tmpLnNo );
cecfc5e7 1636
d12e3536
VZ
1637 // now, enter operation context
1638 mpCurCtx = pOp;
cecfc5e7 1639
8ad74db3 1640 return true;
cecfc5e7
VZ
1641}
1642
1643bool CJSourceParser::ParseArguments( char*& cur )
1644{
d12e3536 1645 // DANGER-MACROS::
cecfc5e7 1646
d12e3536
VZ
1647 // now cursor position is right after the first opening bracket
1648 // of the function declaration
cecfc5e7 1649
d12e3536
VZ
1650 char* blocks [16]; // used exclusivelly for iterative "lean out"
1651 // of macros and misc. not-obviouse grammar
1652 // (dirty,, but we cannot do it very nice,
1653 // we're not preprocessor-free C/C++ code)
1654 int blockSizes[16];
cecfc5e7 1655
d12e3536
VZ
1656 do
1657 {
1658 size_t blocksSkipped = 0;
cecfc5e7 1659
d12e3536 1660 get_next_token( cur );
cecfc5e7 1661
8ad74db3 1662 bool first_blk = true;
cecfc5e7 1663
d12e3536
VZ
1664 while( *cur != ')' && *cur != ',' )
1665 {
1666 blocks[blocksSkipped] = cur;
cecfc5e7 1667
d12e3536
VZ
1668 if ( first_blk )
1669 {
1670 char* prev = cur;
1671 skip_token( cur );
cecfc5e7 1672
d12e3536 1673 blockSizes[blocksSkipped] = size_t(cur-prev);
cecfc5e7 1674
d12e3536
VZ
1675 first_blk = 0;
1676 }
1677 else
1678 blockSizes[blocksSkipped] = skip_block( cur );
cecfc5e7 1679
d12e3536
VZ
1680 get_next_token( cur );
1681 ++blocksSkipped;
1682 }
cecfc5e7
VZ
1683
1684
d12e3536
VZ
1685 if ( blocksSkipped == 1 )
1686 {
1687 // check if the empty arg. list stressed with "void" inside
f71f5a4f
VZ
1688 if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
1689 {
1690 cur++; // skip ')'
1691
d12e3536 1692 break;
f71f5a4f 1693 }
cecfc5e7 1694
d12e3536
VZ
1695 // FIXME:: TBD:: K&R-style function declarations!
1696
1697 // if only one block enclosed, than it's probably
1698 // some macro, there should be at least two blocks,
1699 // one for argument type and another for it's identifier
8ad74db3 1700 return false;
d12e3536 1701 }
cecfc5e7 1702
d12e3536
VZ
1703 if ( blocksSkipped == 0 )
1704 {
1705 if ( *cur == 10 ) ++_gLineNo;
1706 ++cur; // skip ')'
cecfc5e7 1707
d12e3536
VZ
1708 break; // function without paramters
1709 }
59734eb5 1710
d12e3536
VZ
1711 // we should be in the operation context now
1712 spOperation* pOp = (spOperation*)mpCurCtx;
cecfc5e7 1713
d12e3536 1714 spParameter* pPar = new spParameter();
cecfc5e7 1715
d12e3536
VZ
1716 pOp->AddMember( pPar );
1717 // FOR NOW:: line number is not exact if argument list is mutiline
1718 pPar->mSrcLineNo = get_line_no();
cecfc5e7 1719
d12e3536
VZ
1720 size_t nameBlock = blocksSkipped - 1;
1721 size_t typeBlock = nameBlock - 1;
cecfc5e7 1722
d12e3536
VZ
1723 // check if default values present
1724 if ( *blocks[typeBlock] == '=' )
1725 {
1726 // expressions like "int = 5" are ignored,
1727 // since name for paramters is required
1728 if ( blocksSkipped == 3 )
1729 {
1730 if ( *cur == ')' )
1731 {
1732 ++cur;
1733 break;
1734 }
1735 else
1736 continue;
1737 }
cecfc5e7 1738
d12e3536 1739 pPar->mInitVal = string( blocks[nameBlock], blockSizes[nameBlock] );
cecfc5e7 1740
d12e3536
VZ
1741 nameBlock = nameBlock - 2; // skip '=' token and default value block
1742 typeBlock = nameBlock - 1;
1743 }
cecfc5e7 1744
d12e3536
VZ
1745 // attach comments about the parameter
1746 AttachComments( *pPar, blocks[nameBlock] );
cecfc5e7 1747
d12e3536 1748 // retrieve argument name
8bc17f14 1749 pPar->m_Name = string( blocks[nameBlock], blockSizes[nameBlock] );
cecfc5e7 1750
d12e3536 1751 // retreive argument type
cecfc5e7 1752
d12e3536
VZ
1753 size_t len = blockSizes[ typeBlock ];
1754 len = size_t ( (blocks[ typeBlock ] + len) - blocks[ 0 ] );
cecfc5e7 1755
d12e3536 1756 pPar->mType = string( blocks[0], len );
cecfc5e7 1757
8bc17f14 1758 arrange_indirection_tokens_between( pPar->mType, pPar->m_Name );
cecfc5e7 1759
d12e3536
VZ
1760 if ( *cur == ')' )
1761 {
1762 ++cur;
1763 break;
1764 }
cecfc5e7 1765
d12e3536
VZ
1766 ++cur; // skip comma
1767 get_next_token(cur);
cecfc5e7 1768
d12e3536 1769 } while(1);
cecfc5e7 1770
59734eb5
VZ
1771 // skip possible whitespace between ')' and following "const"
1772 while ( isspace(*cur) )
1773 cur++;
1774
d12e3536
VZ
1775 // check if it was really a function not a macro,
1776 // if so, than it should be terminated with semicolon ';'
1777 // or opening implemenetaton bracket '{'
1778
1779 char* tok = cur;
1780
1781 int tmpLnNo;
1782 store_line_no( tmpLnNo );
1783
8ad74db3
WS
1784 bool result = true;
1785
d12e3536
VZ
1786 do
1787 {
1788 if ( *tok == '{' || *tok == ';' )
1789 {
1790 restore_line_no(tmpLnNo);
8ad74db3 1791 break;
d12e3536
VZ
1792 }
1793
1794 // check for unexpected tokens
1795 if ( *tok == '=' || *tok == '0' )
1796 {
1797 skip_token(tok);
8ad74db3 1798 if ( !get_next_token(tok) ) return false;
d12e3536
VZ
1799 continue;
1800 }
1801
8ad74db3 1802 if ( *tok == '}' ) return false;
d12e3536
VZ
1803
1804 // if initialization list found
1805 if ( *tok == ':' )
1806 {
1807 restore_line_no(tmpLnNo);
8ad74db3 1808 break;
d12e3536
VZ
1809 }
1810
1811 if ( cmp_tokens_fast( tok, "const", 5 ) )
1812 {
59734eb5
VZ
1813 ((spOperation*)mpCurCtx)->mIsConstant = true;
1814
d12e3536 1815 skip_token(tok);
8ad74db3 1816 if ( !get_next_token(tok) ) return false;
d12e3536
VZ
1817 continue;
1818 }
1819
8ad74db3 1820 if ( CheckVisibilty( tok ) ) return false;
cecfc5e7 1821
d12e3536 1822 // if next context found
8ad74db3 1823 if ( is_keyword( tok ) ) return false;
cecfc5e7 1824
d12e3536 1825 skip_token(tok);
8ad74db3 1826 if ( !get_next_token(tok) ) return false;
cecfc5e7 1827
d12e3536 1828 } while(1);
cecfc5e7 1829
8ad74db3 1830 return result;
cecfc5e7
VZ
1831}
1832
1833void CJSourceParser::ParseMemberVar( char*& cur )
1834{
d12e3536 1835 MMemberListT& members = mpCurCtx->GetMembers();
cecfc5e7 1836
8ad74db3 1837 bool firstMember = true;
cecfc5e7 1838
d12e3536 1839 string type;
cecfc5e7 1840
d12e3536
VZ
1841 // jump to the end of statement
1842 // and start collecting same-type varibles
1843 // back-to-front towards the type identifier
cecfc5e7 1844
d12e3536
VZ
1845 skip_statement( cur );
1846 char* savedPos = cur;
cecfc5e7 1847
d12e3536
VZ
1848 int tmpLnNo;
1849 store_line_no( tmpLnNo );
cecfc5e7
VZ
1850
1851 --cur; // rewind back to ';'
1852
d12e3536
VZ
1853 do
1854 {
1855 spAttribute* pAttr = new spAttribute();
1856 // FOR NOW:: line not is not exact, if member declaration is multiline
1857 pAttr->mSrcLineNo = get_line_no();
cecfc5e7 1858
d12e3536
VZ
1859 mpCurCtx->AddMember( pAttr );
1860 pAttr->mVisibility = mCurVis;
cecfc5e7 1861
d12e3536 1862 pAttr->mIsConstant = 0;
cecfc5e7 1863
d12e3536
VZ
1864 if ( firstMember )
1865 {
1866 firstMember = 0;
d12e3536 1867 }
cecfc5e7 1868
d12e3536 1869 skip_token_back( cur );
cecfc5e7 1870
d12e3536
VZ
1871 // attach comments about the attribute
1872 AttachComments( *pAttr, cur );
cecfc5e7 1873
8bc17f14 1874 pAttr->m_Name = get_token_str( cur );
cecfc5e7 1875
d12e3536
VZ
1876 // guessing that this going to be variable type
1877 skip_next_token_back( cur );
1878 skip_token_back( cur );
1879
1880 pAttr->mType = get_token_str( cur );
cecfc5e7 1881
d12e3536
VZ
1882 // if comma, than variable list continues
1883 // otherwise the variable type reached - stop
cecfc5e7 1884
d12e3536
VZ
1885 if ( *cur == '=' )
1886 {
1887 // yes, we've mistaken, it was not a identifier,
1888 // but it's default value
1889 pAttr->mInitVal =
8bc17f14 1890 pAttr->m_Name;
cecfc5e7 1891
d12e3536
VZ
1892 // skip default value and '=' symbol
1893 skip_next_token_back( cur );
1894 skip_token_back( cur );
cecfc5e7 1895
8bc17f14 1896 pAttr->m_Name = get_token_str( cur );
cecfc5e7 1897
d12e3536
VZ
1898 skip_next_token_back( cur );
1899 skip_token_back( cur );
1900 }
cecfc5e7 1901
d12e3536
VZ
1902 if ( *cur != ',' )
1903 {
1904 type = get_token_str( cur );
1905 break;
1906 }
cecfc5e7 1907
d12e3536 1908 } while(1);
cecfc5e7 1909
8ad74db3 1910 size_t first = 0;
cecfc5e7 1911
d12e3536
VZ
1912 // set up types for all collected (same-type) attributes;
1913 while ( first != members.size() - 1 )
1914 {
1915 spAttribute* pAttr = members[first++]->CastToAttribute();
1916 if ( !pAttr )
1917 continue;
cecfc5e7 1918
42389ac7 1919 if ( pAttr->mType.empty() )
d12e3536
VZ
1920 pAttr->mType = type;
1921 pAttr->mVisibility = mCurVis;
cecfc5e7 1922
8bc17f14
WS
1923 if ( !pAttr->m_Name.empty() )
1924 arrange_indirection_tokens_between( pAttr->mType, pAttr->m_Name );
d12e3536 1925 }
cecfc5e7 1926
d12e3536
VZ
1927 cur = savedPos;
1928 restore_line_no( tmpLnNo );
cecfc5e7 1929
d12e3536 1930 clear_commets_queue();
cecfc5e7
VZ
1931
1932
1933}
1934
1935void CJSourceParser::SkipFunction( char*& cur )
1936{
d12e3536
VZ
1937 while ( *cur != '(' && cur < _gSrcEnd )
1938 {
1939 if (*cur == 10 ) ++_gLineNo;
1940 ++cur;
1941 }
cecfc5e7 1942
d12e3536
VZ
1943 skip_next_token_back( cur ); // go back and skip function identifier
1944 skip_token_back( cur ); // go back and skip return type
cecfc5e7 1945
d12e3536 1946 skip_block( cur ); // now, go ahead and skip whole declaration
cecfc5e7 1947
d12e3536 1948 SkipFunctionBody( cur );
cecfc5e7
VZ
1949
1950}
1951
1952void CJSourceParser::SkipFunctionBody( char*& cur )
1953{
d12e3536 1954 // FIXME:: check for comments and quoted stirngs here
cecfc5e7 1955
8ad74db3 1956 bool hasDefinition = false;
cecfc5e7 1957
d12e3536
VZ
1958 while( *cur != '{' && *cur != ';' )
1959 {
1960 if (*cur == 10 ) ++_gLineNo;
1961 ++cur;
1962 }
cecfc5e7 1963
d12e3536
VZ
1964 if ( *cur == ';' )
1965 {
1966 ++cur;
1967 }
1968 else
1969 {
8ad74db3 1970 hasDefinition = true;
cecfc5e7 1971
d12e3536
VZ
1972 skip_scope_block( cur ); // skip the whole imp.
1973 }
cecfc5e7 1974
d12e3536
VZ
1975 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1976 {
1977 spOperation& op = *((spOperation*)mpCurCtx);
cecfc5e7 1978
d12e3536 1979 int curOfs = int ( cur - _gSrcStart );
cecfc5e7 1980
d12e3536 1981 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
cecfc5e7 1982
d12e3536 1983 op.mHasDefinition = hasDefinition;
cecfc5e7 1984
d12e3536 1985 // separate scope resolution token from the name of operation
cecfc5e7 1986
8bc17f14 1987 for( size_t i = 0; i != op.m_Name.length(); ++i )
d12e3536 1988 {
8bc17f14 1989 if ( op.m_Name[i] == ':' && op.m_Name[i+1] == ':' )
d12e3536 1990 {
8bc17f14 1991 string unscoped( op.m_Name, i+2, op.m_Name.length() - ( i + 2 ) );
cecfc5e7 1992
8bc17f14 1993 op.mScope = string( op.m_Name, 0, i );
cecfc5e7 1994
8bc17f14 1995 op.m_Name = unscoped;
cecfc5e7 1996
d12e3536
VZ
1997 break;
1998 }
1999 }
2000 }
cecfc5e7
VZ
2001}
2002
2003bool CJSourceParser::CheckVisibilty( char*& cur )
2004{
d12e3536
VZ
2005 size_t len = get_token_len( cur );
2006
2007 if ( cmp_tokens_fast( cur, "public:", len ) )
2008 {
2009 mCurVis = SP_VIS_PUBLIC;
8ad74db3 2010 return true;
d12e3536
VZ
2011 }
2012
2013 if ( cmp_tokens_fast( cur, "protected:", len ) )
2014 {
2015 mCurVis = SP_VIS_PROTECTED;
8ad74db3 2016 return true;
d12e3536
VZ
2017 }
2018
2019 if ( cmp_tokens_fast( cur, "private:", len ) )
2020 {
2021 mCurVis = SP_VIS_PRIVATE;
8ad74db3 2022 return true;
d12e3536
VZ
2023 }
2024
8ad74db3 2025 return false;
cecfc5e7
VZ
2026}
2027
2028void CJSourceParser::AddClassNode( char*& cur )
2029{
d12e3536
VZ
2030 char* ctxStart = cur;
2031
2032 string classkeyword = get_token_str( cur );
2033
2034 skip_token( cur ); // skip 'class' keyword
2035 if ( !get_next_token( cur ) ) return;
2036
2037 // in C++
2038 if ( *cur == ':' )
2039 {
2040 skip_token( cur );
2041 get_next_token( cur );
2042 }
cecfc5e7 2043
d12e3536
VZ
2044 // by default all class members are private
2045 mCurVis = SP_VIS_PRIVATE;
cecfc5e7 2046
d12e3536
VZ
2047 spClass* pClass = new spClass();
2048 if ( classkeyword == "class" )
2049 pClass->mClassSubType = SP_CLTYPE_CLASS;
2050 else if ( classkeyword == "struct" ) {
2051 pClass->mClassSubType = SP_CLTYPE_STRUCTURE;
cecfc5e7 2052
d12e3536
VZ
2053 mCurVis = SP_VIS_PUBLIC;
2054 }
2055 else if ( classkeyword == "union" ) {
2056 pClass->mClassSubType = SP_CLTYPE_UNION;
cecfc5e7 2057
d12e3536
VZ
2058 mCurVis = SP_VIS_PUBLIC;
2059 }
2060 else if ( classkeyword == "interface" )
2061 pClass->mClassSubType = SP_CLTYPE_INTERFACE;
2062 else {
2063 pClass->mClassSubType = SP_CLTYPE_INVALID;
cecfc5e7 2064
d12e3536
VZ
2065 wxFAIL_MSG("unknown class keyword");
2066 }
cecfc5e7 2067
d12e3536 2068 mpCurCtx->AddMember( pClass );
cecfc5e7 2069
d12e3536
VZ
2070 // attach comments about the class
2071 AttachComments( *pClass, cur );
cecfc5e7 2072
d12e3536 2073 pClass->mSrcLineNo = get_line_no();
cecfc5e7 2074
d12e3536 2075 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
cecfc5e7 2076
d12e3536 2077 char* nameTok = cur;
8bc17f14 2078 pClass->m_Name = get_token_str( cur );
cecfc5e7 2079
d12e3536 2080 bool isDerived = 0;
cecfc5e7 2081
d12e3536 2082 // DANGER-MACROS::
cecfc5e7 2083
d12e3536
VZ
2084 do
2085 {
2086 skip_token( cur );
2087 if ( !get_next_token( cur ) ) return;
cecfc5e7 2088
d12e3536
VZ
2089 if ( *cur == ':' )
2090 {
2091 isDerived = 1;
cecfc5e7 2092
d12e3536 2093 char* tok = cur;
cecfc5e7 2094
d12e3536
VZ
2095 int tmpLn;
2096 store_line_no( tmpLn );
cecfc5e7 2097
d12e3536
VZ
2098 skip_next_token_back( tok );
2099 skip_token_back( tok );
cecfc5e7 2100
d12e3536 2101 restore_line_no( tmpLn );
cecfc5e7 2102
d12e3536
VZ
2103 // class name should precend ':' colon, thus
2104 // the one which was captured before was
2105 // proablty something else (like __dllexport MyClass : ... )
cecfc5e7 2106
d12e3536
VZ
2107 if ( nameTok != tok )
2108 {
8bc17f14 2109 pClass->m_Name = get_token_str( tok );
d12e3536 2110 }
cecfc5e7 2111
d12e3536 2112 }
cecfc5e7 2113
d12e3536
VZ
2114 if ( *cur == '{' )
2115 break;
cecfc5e7 2116
d12e3536
VZ
2117 if ( *cur == ',' )
2118 continue;
cecfc5e7 2119
d12e3536 2120 size_t len = get_token_len( cur );
cecfc5e7 2121
d12e3536
VZ
2122 // skip neglectable C++ modifieres
2123 if ( cmp_tokens_fast( cur, "public", len ) )
2124 continue;
cecfc5e7 2125
d12e3536
VZ
2126 if ( cmp_tokens_fast( cur, "protected", len ) )
2127 continue;
cecfc5e7 2128
d12e3536
VZ
2129 if ( cmp_tokens_fast( cur, "private", len ) )
2130 continue;
cecfc5e7 2131
d12e3536
VZ
2132 if ( cmp_tokens_fast( cur, "virtual", len ) )
2133 continue;
cecfc5e7 2134
d12e3536 2135 // skip neglectable JAVA modifieres
cecfc5e7 2136
d12e3536
VZ
2137 if ( cmp_tokens_fast( cur, "extends", len ) )
2138 {
2139 isDerived = 1;
2140 continue;
2141 }
cecfc5e7 2142
d12e3536
VZ
2143 if ( cmp_tokens_fast( cur, "implements", len ) )
2144 {
2145 isDerived = 1;
2146 continue;
2147 }
cecfc5e7 2148
d12e3536 2149 // all we need to know is superclass or interface
cecfc5e7 2150
d12e3536
VZ
2151 char* tok = cur;
2152 int tmpLn;
2153 store_line_no( tmpLn );
cecfc5e7 2154
d12e3536
VZ
2155 skip_token(tok);
2156 get_next_token(tok);
cecfc5e7 2157
d12e3536 2158 restore_line_no( tmpLn );
cecfc5e7 2159
d12e3536 2160 if ( *tok != ':' && *cur != ':' )
cecfc5e7 2161
d12e3536 2162 pClass->mSuperClassNames.push_back( string( cur, len ) );
cecfc5e7 2163
d12e3536 2164 } while(1);
cecfc5e7 2165
d12e3536
VZ
2166 if ( !isDerived )
2167 {
2168 int tmpLn;
2169 store_line_no( tmpLn );
2170
2171 while ( pClass->mSuperClassNames.size() )
2172
2173 pClass->mSuperClassNames.erase( &pClass->mSuperClassNames[0] );
cecfc5e7 2174
d12e3536 2175 char* tok = cur;
cecfc5e7 2176
d12e3536
VZ
2177 // some non-obviouse token was following "class" keyword -
2178 // we've confused it with class name - thus now we're reverting this mistake
cecfc5e7 2179
d12e3536
VZ
2180 skip_next_token_back( tok );
2181 skip_token_back( tok );
cecfc5e7 2182
8bc17f14 2183 pClass->m_Name = get_token_str( tok );
cecfc5e7 2184
d12e3536
VZ
2185 restore_line_no( tmpLn );
2186 }
cecfc5e7
VZ
2187
2188
d12e3536 2189 ++cur; // skip opening curly brace
cecfc5e7 2190
d12e3536 2191 pClass->mHeaderLength = ( cur - ctxStart );
cecfc5e7 2192
d12e3536
VZ
2193 // now, enter the class context
2194 mpCurCtx = pClass;
cecfc5e7 2195
d12e3536 2196 clear_commets_queue();
cecfc5e7
VZ
2197}
2198
2199void CJSourceParser::AddEnumNode( char*& cur )
2200{
d12e3536
VZ
2201 // now the cursor is at "enum" keyword
2202 char* start = cur;
2203
2204 spEnumeration* pEnum = new spEnumeration();
2205 mpCurCtx->AddMember( pEnum );
cecfc5e7 2206
d12e3536 2207 pEnum->mSrcLineNo = get_line_no();
cecfc5e7 2208
cecfc5e7 2209
d12e3536 2210 AttachComments( *pEnum, cur );
cecfc5e7 2211
d12e3536
VZ
2212 skip_token( cur );
2213 if ( !get_next_token( cur ) ) return;
cecfc5e7 2214
d12e3536
VZ
2215 // check if enumeration has got it's identifier
2216 if ( *cur != '{' )
2217 {
8bc17f14 2218 pEnum->m_Name = get_token_str( cur );
d12e3536 2219 }
cecfc5e7 2220
d12e3536 2221 if ( !skip_imp_block( cur ) ) return;
cecfc5e7 2222
d12e3536 2223 get_string_between( start, cur, &pEnum->mEnumContent );
cecfc5e7 2224
d12e3536
VZ
2225 if ( get_next_token(cur) )
2226 {
2227 // check if the identifier if after the {...} block
2228 if ( *cur != ';' )
cecfc5e7 2229
8bc17f14 2230 pEnum->m_Name = get_token_str( cur );
d12e3536 2231 }
cecfc5e7 2232
d12e3536 2233 clear_commets_queue();
cecfc5e7
VZ
2234}
2235
2236void CJSourceParser::AddTypeDefNode( char*& cur )
2237{
d12e3536 2238 // now the cursor at the token next to "typedef" keyword
cecfc5e7 2239
d12e3536 2240 if ( !get_next_token(cur) ) return;
cecfc5e7 2241
d12e3536 2242 char* start = cur;
cecfc5e7 2243
d12e3536
VZ
2244 spTypeDef* pTDef = new spTypeDef();
2245 mpCurCtx->AddMember( pTDef );
cecfc5e7 2246
d12e3536 2247 pTDef->mSrcLineNo = get_line_no();
cecfc5e7 2248
d12e3536 2249 AttachComments( *pTDef, cur );
cecfc5e7 2250
d12e3536 2251 skip_statement( cur );
cecfc5e7 2252
d12e3536
VZ
2253 int tmpLnNo;
2254 store_line_no( tmpLnNo );
cecfc5e7 2255
d12e3536
VZ
2256 char* tok = cur-1;
2257 skip_next_token_back( tok );
cecfc5e7 2258
d12e3536 2259 char* nameEnd = tok;
cecfc5e7 2260
d12e3536 2261 skip_token_back( tok );
cecfc5e7 2262
d12e3536 2263 char* nameStart = tok;
cecfc5e7 2264
d12e3536 2265 skip_next_token_back( tok );
cecfc5e7 2266
d12e3536 2267 char* typeEnd = tok;
cecfc5e7 2268
d12e3536
VZ
2269 // check if it's function prototype
2270 if ( *nameStart == ')' )
2271 {
2272 typeEnd = nameStart+1;
2273
2274 // skip argument list
2275 while ( *nameStart != '(' ) --nameStart;
cecfc5e7 2276
d12e3536
VZ
2277 // skip to function type definition
2278 while ( *nameStart != ')' ) --nameStart;
cecfc5e7 2279
d12e3536 2280 skip_next_token_back( nameStart );
cecfc5e7 2281
d12e3536 2282 nameEnd = nameStart;
cecfc5e7 2283
d12e3536 2284 skip_token_back( nameStart );
cecfc5e7 2285
d12e3536
VZ
2286 if ( *nameStart == '*' ) ++nameStart;
2287 }
cecfc5e7 2288
d12e3536 2289 get_string_between( start, typeEnd, &pTDef->mOriginalType );
cecfc5e7 2290
8bc17f14 2291 get_string_between( nameStart, nameEnd, &pTDef->m_Name );
cecfc5e7 2292
d12e3536 2293 clear_commets_queue();
cecfc5e7 2294
d12e3536 2295 restore_line_no( tmpLnNo );
cecfc5e7 2296}