merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / apps / utils / sdkparse / sdkparse.cpp
1 // sdkparse.cpp
2
3 #ifdef _MSC_VER
4 #pragma warning ( disable : 4786 )
5 #endif//_MSC_VER
6
7 #define WIN32_LEAN_AND_MEAN
8 #include <windows.h>
9
10 #include <string>
11 #include <vector>
12 #include <conio.h>
13
14 #include "EnumFilesImpl.h"
15
16 #include "assert.h"
17 #include "File.h"
18 #include "binary2cstr.h"
19 #include "strip_comments.h"
20 #include "tokenize.h"
21 #include "skip_ws.h"
22 #include "iskeyword.h"
23 #include "Type.h"
24 #include "Header.h"
25
26 #define TOKASSERT(x) \
27 if(!(x))\
28 {\
29 printf("ASSERT FAILURE: (%s) at %s:%i\n", #x, __FILE__, __LINE__);\
30 printf("WHILE PROCESSING: \n");\
31 for ( int ajf83pfj = 0; ajf83pfj < tokens.size(); ajf83pfj++ )\
32 printf("%s ", tokens[ajf83pfj].c_str() );\
33 printf("\n");\
34 _CrtDbgBreak();\
35 }
36 using std::string;
37 using std::vector;
38
39 vector<Header*> headers;
40
41 bool import_file ( const char* filename );
42 char* findend ( char* p, bool& externc );
43 Type identify ( const vector<string>& tokens, int off = 0 );
44 Type process ( const string& element, vector<string>& names, bool& isTypedef, vector<string>& dependencies );
45 void process_preprocessor ( const char* filename, Header& h, const string& element );
46 void process_c ( Header& h, const string& element );
47 int parse_type ( Type t, const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
48 int parse_ignored_statement ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
49 int parse_tident ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
50 int parse_variable ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
51 int parse_struct ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
52 int parse_function ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
53 int parse_function_ptr ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
54 int parse_ifwhile ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
55 int parse_do ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
56
57 const char* libc_includes[] =
58 {
59 "basestd.h",
60 "except.h",
61 "float.h",
62 "limits.h",
63 "stdarg.h",
64 "stddef.h",
65 "stdlib.h",
66 "string.h",
67 "types.h"
68 };
69
70 bool is_libc_include ( const string& inc )
71 {
72 string s ( inc );
73 strlwr ( &s[0] );
74 for ( int i = 0; i < sizeof(libc_includes)/sizeof(libc_includes[0]); i++ )
75 {
76 if ( s == libc_includes[i] )
77 return true;
78 }
79 return false;
80 }
81
82 BOOL FileEnumProc ( PWIN32_FIND_DATA pwfd, const char* filename, long lParam )
83 {
84 if ( !is_libc_include ( filename ) )
85 import_file ( filename );
86 return TRUE;
87 }
88
89 void main()
90 {
91 //import_file ( "coff.h" );
92
93 File f ( "input.lst", "r" );
94 if ( !f.isopened() )
95 {
96 printf ( "Couldn't open \"input.lst\" for input\nPress any key to exit\n" );
97 (void)getch();
98 return;
99 }
100 string filename;
101 while ( f.next_line ( filename, true ) )
102 import_file ( filename.c_str() );
103 //printf ( "press any key to start\n" );
104 //getch();
105 /*#if 1
106 import_file ( "../test.h" );
107 #else
108 EnumFilesInDirectory ( "c:/cvs/reactos/apps/utils/sdkparse/include", "*.h", FileEnumProc, 0, TRUE, FALSE );
109 #endif*/
110 printf ( "Done!\nPress any key to exit!\n" );
111 (void)getch();
112 }
113
114 bool import_file ( const char* filename )
115 {
116 int i;
117
118 for ( i = 0; i < headers.size(); i++ )
119 {
120 if ( headers[i]->filename == filename )
121 return true;
122 }
123
124 string s;
125 if ( !File::LoadIntoString ( s, filename ) )
126 {
127 printf ( "Couldn't load \"%s\" for input.\n", filename );
128 ASSERT(0);
129 }
130
131 printf ( "%s\n", filename );
132
133 // strip comments from the file...
134 strip_comments ( s, true );
135
136 /*{
137 string no_comments ( filename );
138 no_comments += ".nocom.txt";
139 File::SaveFromString ( no_comments.c_str(), s, false );
140 }*/
141
142 Header* h = new Header ( filename );
143 headers.push_back ( h );
144
145 char* p = &s[0];
146 while ( p )
147 {
148 // skip whitespace
149 p = skip_ws ( p );
150 if ( !*p )
151 break;
152 // check for pre-processor command
153 if ( *p == '#' )
154 {
155 char* end = strchr ( p, '\n' );
156 while ( end && end[-1] == '\\' )
157 end = strchr ( end+1, '\n' );
158 if ( !end )
159 end = p + strlen(p);
160 string element ( p, end-p );
161
162 process_preprocessor ( filename, *h, element );
163
164 p = end;
165 }
166 else if ( *p == '}' && h->externc )
167 {
168 p++;
169 p = skip_ws ( p );
170
171 if ( *p == ';' ) p++;
172 }
173 else
174 {
175 bool externc = false;
176 char* end = findend ( p, externc );
177 ASSERT(end);
178 if ( externc )
179 h->externc = true;
180 else
181 {
182 string element ( p, end-p );
183
184 process_c ( *h, element );
185 }
186 p = end;
187 }
188 }
189 h->done = true;
190 return true;
191 }
192
193 string get_hdrguardtext ( const char* filename )
194 {
195 string s ( filename );
196 char* p = &s[0];
197 char* p2;
198 while ( (p2 = strchr(p, '\\')) )
199 *p2 = '/';
200 while ( (p2 = strchr(p,'/')) )
201 p = p2 + 1;
202 char* end = strchr ( p, '.' );
203 ASSERT(end);
204 while ( (p2 = strchr(end+1,'.')) )
205 end = p2;
206 string hdrguardtext ( p, end-p );
207 strupr ( &hdrguardtext[0] );
208 return hdrguardtext;
209 }
210
211 void process_preprocessor ( const char* filename, Header& h, const string& element )
212 {
213 string hdrguardtext ( get_hdrguardtext ( filename ) );
214
215 const char* p = &element[0];
216 ASSERT ( *p == '#' );
217 p++;
218 p = skip_ws ( p );
219 const char* end = p;
220 while ( iscsym(*end) )
221 end++;
222 string preproc ( p, end-p );
223 p = end+1;
224 p = skip_ws ( p );
225
226 const string dbg_filename = "napi/lpc.h DISABLE DISABLE DISABLE";
227
228 if ( preproc == "include" )
229 {
230 //if ( h.filename == "napi/lpc.h" )
231 // _CrtDbgBreak();
232 ASSERT ( *p == '<' || *p == '\"' );
233 p++;
234 p = skip_ws ( p );
235 const char* end = strpbrk ( p, ">\"" );
236 if ( !end )
237 end = p + strlen(p);
238 while ( end > p && isspace(end[-1]) )
239 end--;
240 string include_filename ( p, end-p );
241 if ( is_libc_include ( include_filename ) )
242 h.libc_includes.push_back ( include_filename );
243 else
244 {
245 bool loaded = false;
246 for ( int i = 0; i < headers.size() && !loaded; i++ )
247 {
248 if ( headers[i]->filename == include_filename )
249 {
250 if ( !headers[i]->done )
251 {
252 printf ( "circular dependency between '%s' and '%s'\n", filename, include_filename.c_str() );
253 ASSERT ( 0 );
254 }
255 loaded = true;
256 }
257 }
258 if ( !loaded )
259 {
260 printf ( "(diverting to '%s')\n", include_filename.c_str() );
261 import_file ( include_filename.c_str() );
262 printf ( "(now back to '%s')\n", filename );
263 }
264 h.includes.push_back ( include_filename );
265 }
266 }
267 else if ( preproc == "define" )
268 {
269 size_t len = element.size();
270 if ( strstr ( element.c_str(), hdrguardtext.c_str() )
271 && element[len-2] == '_'
272 && element[len-1] == 'H' )
273 {
274 // header include guard... ignore!
275 return;
276 }
277 Symbol *s = new Symbol;
278 s->type = T_DEFINE;
279
280 p += 6;
281 p = skip_ws ( p );
282
283 const char* end = p;
284 while ( iscsym(*end) )
285 end++;
286
287 s->names.push_back ( string(p,end-p) );
288
289 s->definition = element;
290
291 h.symbols.push_back ( s );
292 }
293 else if ( preproc == "undef" )
294 {
295 // safely ignoreable for now, I think
296 }
297 else if ( preproc == "if" || preproc == "ifdef" || preproc == "ifndef" )
298 {
299 if ( dbg_filename == h.filename )
300 printf ( "(%s) PRE-PUSH preproc stack = %lu\n", preproc.c_str(), h.ifs.size() );
301 size_t len = element.size();
302 // check for header include guard...
303 if ( strstr ( element.c_str(), hdrguardtext.c_str() )
304 && element[len-2] == '_'
305 && element[len-1] == 'H' )
306 h.ifs.push_back ( string("") );
307 else
308 h.ifs.push_back ( element );
309 h.ifspreproc.push_back ( preproc );
310 if ( dbg_filename == h.filename )
311 printf ( "POST-PUSH preproc stack = %lu\n", h.ifs.size() );
312 }
313 else if ( preproc == "endif" )
314 {
315 if ( dbg_filename == h.filename )
316 printf ( "(%s) PRE-POP preproc stack = %lu\n", preproc.c_str(), h.ifs.size() );
317 ASSERT ( h.ifs.size() > 0 && h.ifs.size() == h.ifspreproc.size() );
318 h.ifs.pop_back();
319 h.ifspreproc.pop_back();
320 if ( dbg_filename == h.filename )
321 printf ( "POST-POP preproc stack = %lu\n", h.ifs.size() );
322 }
323 else if ( preproc == "elif" )
324 {
325 if ( dbg_filename == h.filename )
326 printf ( "(%s) PRE-PUSHPOP preproc stack = %lu\n", preproc.c_str(), h.ifs.size() );
327 string& oldpre = h.ifspreproc.back();
328 string old = h.ifs.back();
329 string condold;
330 if ( oldpre == "ifdef" )
331 condold = string("!defined(") + old + ")";
332 else if ( oldpre == "ifndef" )
333 condold = string("defined(") + old + ")";
334 else if ( oldpre == "if" )
335 condold = string("!(") + old + ")";
336 else
337 {
338 printf ( "unrecognized preproc '%s'\n", oldpre.c_str() );
339 ASSERT(0);
340 return;
341 }
342 h.ifs.back() = string("(") + element + ") && " + condold;
343 h.ifspreproc.back() = "if";
344 if ( dbg_filename == h.filename )
345 printf ( "POST-PUSHPOP preproc stack = %lu\n", h.ifs.size() );
346 }
347 else if ( preproc == "else" )
348 {
349 if ( dbg_filename == h.filename )
350 printf ( "(%s) PRE-PUSHPOP preproc stack = %lu\n", preproc.c_str(), h.ifs.size() );
351 string& oldpre = h.ifspreproc.back();
352 ASSERT ( oldpre != "else" );
353 if ( oldpre == "ifdef" )
354 h.ifs.back() = "ifndef";
355 else if ( oldpre == "ifndef" )
356 h.ifs.back() = "ifdef";
357 else if ( oldpre == "if" )
358 h.ifs.back() = string("!(") + h.ifs.back() + ")";
359 else
360 {
361 printf ( "unrecognized preproc '%s'\n", oldpre.c_str() );
362 ASSERT(0);
363 return;
364 }
365 oldpre = "else";
366 if ( dbg_filename == h.filename )
367 printf ( "POST-PUSHPOP preproc stack = %lu\n", h.ifs.size() );
368 }
369 else if ( preproc == "include_next" )
370 {
371 // we can safely ignore this command...
372 }
373 else if ( preproc == "pragma" )
374 {
375 h.pragmas.push_back ( element );
376 }
377 else if ( preproc == "error" )
378 {
379 // FIXME - how to handle these
380 }
381 else
382 {
383 printf ( "process_preprocessor() choked on '%s'\n", preproc.c_str() );
384 }
385 }
386
387 void process_c ( Header& h, const string& element )
388 {
389 //printf ( "\"%s\"\n\n", binary2cstr(element).c_str() );
390
391 bool isTypedef;
392
393 Symbol *s = new Symbol;
394 s->definition = element;
395 s->type = process ( element, s->names, isTypedef, s->dependencies );
396
397 for ( int i = 0; i < h.ifs.size(); i++ )
398 {
399 if ( h.ifs[i].size() )
400 s->ifs.push_back ( h.ifs[i] );
401 }
402
403 /*printf ( "names: " );
404 if ( s->names.size() )
405 {
406 printf ( "%s", s->names[0].c_str() );
407 for ( int i = 1; i < s->names.size(); i++ )
408 printf ( ", %s", s->names[i].c_str() );
409 }
410 else
411 printf ( "(none)" );
412 printf ( "\n\n" );
413
414 printf ( "dependencies: " );
415 if ( s->dependencies.size() )
416 {
417 printf ( "%s", s->dependencies[0].c_str() );
418 for ( int i = 1; i < s->dependencies.size(); i++ )
419 printf ( ", %s", s->dependencies[i].c_str() );
420 }
421 else
422 printf ( "(none)" );
423 printf ( "\n\n" );*/
424
425 h.symbols.push_back ( s );
426 }
427
428 char* skipsemi ( char* p )
429 {
430 if ( *p != '{' ) // }
431 {
432 ASSERT(0);
433 }
434 p++;
435 for ( ;; )
436 {
437 char* s = strchr ( p, '{' );
438 char* e = strchr ( p, '}' );
439 if ( !e )
440 e = p + strlen(p);
441 if ( !s || s > e )
442 {
443 // make sure we don't return pointer past null
444 if ( *e )
445 return e + 1;
446 else
447 return e;
448 }
449 p = skipsemi ( s );
450 }
451 }
452
453 char* findend ( char* p, bool& externc )
454 {
455 //if ( !strncmp ( p, "typedef struct _OSVERSIONINFOEXA : ", 35 ) )
456 // _CrtDbgBreak();
457 // special-case for 'extern "C"'
458 if ( !strncmp ( p, "extern", 6 ) )
459 {
460 char* p2 = p + 6;
461 p2 = skip_ws ( p2 );
462 if ( !strncmp ( p2, "\"C\"", 3 ) )
463 {
464 p2 += 3;
465 p2 = skip_ws ( p2 );
466 if ( *p2 == '{' )
467 {
468 externc = true;
469 return p2+1;
470 }
471 }
472 }
473 // special-case for 'typedef_tident'
474 if ( !strncmp ( p, "typedef_tident", 14 ) )
475 {
476 char* end = strchr ( p, ')' );
477 ASSERT(end);
478 return end+1;
479 }
480 externc = false;
481 bool isStruct = false;
482
483 char* end = strchr ( p, ';' );
484 if ( !end )
485 end = p + strlen(p);
486 else
487 end++;
488 char* semi = strchr ( p, '{' );
489 if ( !semi || semi > end )
490 return end;
491 end = skipsemi ( semi );
492
493 const char* structs[] = { "struct", "enum", "class", "union" };
494 for ( int i = 0; i < sizeof(structs)/sizeof(structs[0]); i++ )
495 {
496 char* pStruct = strstr ( p, structs[i] );
497 if ( pStruct
498 && pStruct < semi
499 && !__iscsym(pStruct[-1])
500 && !__iscsym(pStruct[strlen(structs[i])]) )
501 {
502 // make sure there's at most one identifier followed
503 // by a {
504 pStruct += strlen(structs[i]);
505 pStruct = skip_ws ( pStruct );
506 if ( __iscsymf(*pStruct) )
507 {
508 while ( __iscsym(*pStruct) )
509 pStruct++;
510 pStruct = skip_ws ( pStruct );
511 }
512 // special exception - C++ classes & stuff
513 if ( *pStruct == ':' )
514 {
515 pStruct = skip_ws ( pStruct + 1 );
516 ASSERT ( !strncmp(pStruct,"public",6) || !strncmp(pStruct,"protected",9) || !strncmp(pStruct,"private",7) );
517 // skip access:
518 while ( __iscsym(*pStruct) )
519 pStruct++;
520 pStruct = skip_ws ( pStruct );
521 // skip base-class-name:
522 ASSERT ( __iscsymf(*pStruct) );
523 while ( __iscsym(*pStruct) )
524 pStruct++;
525 pStruct = skip_ws ( pStruct );
526 }
527 if ( *pStruct == '{' )
528 isStruct = true;
529 break;
530 }
531 }
532
533 if ( isStruct )
534 {
535 end = strchr ( end, ';' );
536 if ( !end )
537 end = p + strlen(p);
538 else
539 end++;
540 }
541 else
542 {
543 char* p2 = skip_ws ( end );
544 if ( *p2 == ';' )
545 end = p2 + 1;
546 }
547 return end;
548 }
549
550 int skip_declspec ( const vector<string>& tokens, int off )
551 {
552 if ( tokens[off] == "__declspec" )
553 {
554 off++;
555 TOKASSERT ( tokens[off] == "(" );
556 off++;
557 int parens = 1;
558 while ( parens )
559 {
560 if ( tokens[off] == "(" )
561 parens++;
562 else if ( tokens[off] == ")" )
563 parens--;
564 off++;
565 }
566 }
567 return off;
568 }
569
570 Type identify ( const vector<string>& tokens, int off )
571 {
572 off = skip_declspec ( tokens, off );
573 /*if ( tokens.size() > off+4 )
574 {
575 if ( tokens[off+4] == "PCONTROLDISPATCHER" )
576 _CrtDbgBreak();
577 }*/
578 /*if ( tokens.size() > off+1 )
579 {
580 if ( tokens[off+1] == "_OSVERSIONINFOEXA" )
581 _CrtDbgBreak();
582 }*/
583 if ( tokens[off] == "__asm__" )
584 return T_IGNORED_STATEMENT;
585 else if ( tokens[off] == "return" )
586 return T_IGNORED_STATEMENT;
587 else if ( tokens[off] == "typedef_tident" )
588 return T_TIDENT;
589 else if ( tokens[off] == "if" )
590 return T_IF;
591 else if ( tokens[off] == "while" )
592 return T_WHILE;
593 else if ( tokens[off] == "do" )
594 return T_DO;
595 int openparens = 0;
596 int closeparens = 0;
597 int brackets = 0;
598 for ( int i = off; i < tokens.size(); i++ )
599 {
600 if ( tokens[i] == "(" && !brackets )
601 openparens++;
602 else if ( tokens[i] == ")" && !brackets && openparens == 1 )
603 closeparens++;
604 else if ( tokens[i] == "{" )
605 brackets++;
606 else if ( (tokens[i] == "struct" || tokens[i] == "union") && !openparens )
607 {
608 for ( int j = i + 1; j < tokens.size(); j++ )
609 {
610 if ( tokens[j] == "{" )
611 return T_STRUCT;
612 else if ( tokens[j] == "(" || tokens[j] == ";" || tokens[j] == "*" )
613 break;
614 }
615 }
616 else if ( tokens[i] == ";" )
617 break;
618 else if ( tokens[i] == "__attribute__" )
619 break;
620 }
621 if ( openparens > 1 && closeparens )
622 return T_FUNCTION_PTR;
623 else if ( openparens >= 1 )
624 return T_FUNCTION;
625 return T_VARIABLE;
626 }
627
628 Type process ( const string& element, vector<string>& names, bool& isTypedef, vector<string>& dependencies )
629 {
630 names.resize ( 0 );
631 isTypedef = false;
632 dependencies.resize ( 0 );
633
634 vector<string> tokens;
635
636 tokenize ( element, tokens );
637
638 // now let's do the classification...
639 int i = 0;
640 if ( tokens[i] == "typedef" )
641 {
642 isTypedef = true;
643 i++;
644 }
645
646 Type t = identify ( tokens, i );
647
648 parse_type ( t, tokens, i, names, dependencies );
649
650 return t;
651 }
652
653 int parse_type ( Type t, const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
654 {
655 switch ( t )
656 {
657 case T_IGNORED_STATEMENT:
658 return parse_ignored_statement ( tokens, off, names, dependencies );
659 case T_TIDENT:
660 return parse_tident ( tokens, off, names, dependencies );
661 case T_VARIABLE:
662 return parse_variable ( tokens, off, names, dependencies );
663 case T_STRUCT:
664 return parse_struct ( tokens, off, names, dependencies );
665 case T_FUNCTION:
666 return parse_function ( tokens, off, names, dependencies );
667 case T_FUNCTION_PTR:
668 return parse_function_ptr ( tokens, off, names, dependencies );
669 case T_IF:
670 case T_WHILE:
671 return parse_ifwhile ( tokens, off, names, dependencies );
672 case T_DO:
673 return parse_do ( tokens, off, names, dependencies );
674 default:
675 TOKASSERT(!"unidentified type in parse_type()");
676 return 0;
677 }
678 }
679
680 void name ( const string& ident, vector<string>& names )
681 {
682 if ( !__iscsymf ( ident[0] ) )
683 return;
684 if ( iskeyword ( ident ) )
685 return;
686 for ( int i = 0; i < names.size(); i++ )
687 {
688 if ( names[i] == ident )
689 return;
690 }
691 names.push_back ( ident );
692 }
693
694 void depend ( const string& ident, vector<string>& dependencies )
695 {
696 if ( !__iscsymf ( ident[0] ) )
697 return;
698 if ( iskeyword ( ident ) )
699 return;
700 for ( int i = 0; i < dependencies.size(); i++ )
701 {
702 if ( dependencies[i] == ident )
703 return;
704 }
705 dependencies.push_back ( ident );
706 }
707
708 int parse_ignored_statement ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
709 {
710 off++;
711 while ( tokens[off] != ";" )
712 off++;
713 ASSERT ( tokens[off] == ";" );
714 return off + 1;
715 }
716
717 int parse_tident ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
718 {
719 TOKASSERT ( tokens[off] == "typedef_tident" );
720 TOKASSERT ( tokens[off+1] == "(" && tokens[off+3] == ")" );
721 names.push_back ( tokens[off+2] );
722 dependencies.push_back ( "typedef_tident" );
723 return off + 4;
724 }
725
726 int parse_variable ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
727 {
728 // NOTE - Test with bitfields, I think this code will actually handle them properly...
729 if ( tokens[off] == ";" )
730 return off + 1;
731 depend ( tokens[off++], dependencies );
732 int done = tokens.size();
733 while ( off < tokens.size() && tokens[off] != ";" )
734 name ( tokens[off++], names );
735 TOKASSERT ( off < tokens.size() && tokens[off] == ";" );
736 return off + 1;
737 }
738
739 int parse_struct ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
740 {
741 int done = tokens.size();
742
743 //if ( tokens[off+1] == "_LARGE_INTEGER" )
744 // _CrtDbgBreak();
745
746 while ( off < done && tokens[off] != "struct" && tokens[off] != "union" )
747 depend ( tokens[off++], dependencies );
748
749 TOKASSERT ( tokens[off] == "struct" || tokens[off] == "union" );
750 if ( tokens[off] != "struct" && tokens[off] != "union" )
751 return off;
752 off++;
753
754 if ( tokens[off] != "{" )
755 name ( tokens[off++], names );
756
757 if ( tokens[off] == ":" )
758 {
759 off++;
760 TOKASSERT ( tokens[off] == "public" || tokens[off] == "protected" || tokens[off] == "private" );
761 off++;
762 depend ( tokens[off++], dependencies );
763 }
764
765 TOKASSERT ( tokens[off] == "{" );
766 off++;
767
768 // skip through body of struct - noting any dependencies
769 int indent = 1;
770 //if ( off >= done ) _CrtDbgBreak();
771 while ( off < done && tokens[off] != "}" )
772 {
773 vector<string> fauxnames;
774 Type t = identify ( tokens, off );
775 off = parse_type ( t, tokens, off, fauxnames, dependencies );
776 //if ( off >= done ) _CrtDbgBreak();
777 }
778
779 // process any trailing dependencies/names...
780 while ( tokens[off] != ";" )
781 {
782 TOKASSERT ( off+1 < done );
783 if ( tokens[off+1] == "," || tokens[off+1] == ";" )
784 name ( tokens[off], names );
785 else
786 depend ( tokens[off], dependencies );
787 off++;
788 }
789
790 TOKASSERT ( tokens[off] == ";" );
791 off++;
792
793 return off;
794 }
795
796 int parse_param ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
797 {
798 if ( tokens[off] == ")" )
799 return off;
800 // special-case check for function pointer params
801 int done = off;
802 int parens = 1;
803 bool fptr = false;
804 for ( ;; )
805 {
806 if ( tokens[done] == "," && parens == 1 )
807 break;
808 if ( tokens[done] == ")" )
809 {
810 if ( parens == 1 )
811 break;
812 else
813 parens--;
814 }
815 if ( tokens[done] == "(" )
816 parens++;
817 if ( tokens[done] == "*" && tokens[done-1] == "(" )
818 fptr = true;
819 done++;
820 }
821 if ( !fptr )
822 done--;
823 while ( off < done )
824 depend ( tokens[off++], dependencies );
825 if ( !fptr )
826 name ( tokens[off++], names );
827 return off;
828 }
829
830 int parse_function ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
831 {
832 vector<string> fauxnames;
833
834 off = skip_declspec ( tokens, off );
835
836 while ( tokens[off+1] != "(" )
837 depend ( tokens[off++], dependencies );
838 name ( tokens[off++], names );
839
840 TOKASSERT ( tokens[off] == "(" );
841
842 while ( tokens[off] != ")" )
843 {
844 off++;
845 off = parse_param ( tokens, off, fauxnames, dependencies );
846 TOKASSERT ( tokens[off] == "," || tokens[off] == ")" );
847 }
848
849 off++;
850
851 // check for "attributes"
852 if ( tokens[off] == "__attribute__" )
853 {
854 off++;
855 TOKASSERT ( tokens[off] == "(" );
856 off++;
857 int parens = 1;
858 while ( parens )
859 {
860 if ( tokens[off] == "(" )
861 parens++;
862 else if ( tokens[off] == ")" )
863 parens--;
864 off++;
865 }
866 }
867
868 // is this just a function *declaration* ?
869 if ( tokens[off] == ";" )
870 return off;
871
872 // we have a function body...
873 TOKASSERT ( tokens[off] == "{" );
874 off++;
875
876 while ( tokens[off] != "}" )
877 {
878 Type t = identify ( tokens, off );
879 if ( t == T_VARIABLE )
880 off = parse_type ( t, tokens, off, fauxnames, dependencies );
881 else
882 {
883 while ( tokens[off] != ";" )
884 off++;
885 TOKASSERT ( tokens[off] == ";" );
886 off++;
887 }
888 }
889
890 TOKASSERT ( tokens[off] == "}" );
891 off++;
892
893 return off;
894 }
895
896 int parse_function_ptr ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
897 {
898 off = skip_declspec ( tokens, off );
899
900 while ( tokens[off] != "(" )
901 depend ( tokens[off++], dependencies );
902
903 TOKASSERT ( tokens[off] == "(" );
904 off++;
905
906 while ( tokens[off+1] != ")" )
907 depend ( tokens[off++], dependencies );
908 name ( tokens[off++], names );
909
910 TOKASSERT ( tokens[off] == ")" );
911
912 off++;
913
914 TOKASSERT ( tokens[off] == "(" );
915
916 while ( tokens[off] != ")" )
917 {
918 off++;
919 vector<string> fauxnames;
920 off = parse_param ( tokens, off, fauxnames, dependencies );
921 TOKASSERT ( tokens[off] == "," || tokens[off] == ")" );
922 }
923
924 off++;
925 TOKASSERT ( tokens[off] == ";" );
926 off++;
927 return off;
928 }
929
930 int parse_ifwhile ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
931 {
932 TOKASSERT ( tokens[off] == "if" || tokens[off] == "while" );
933 off++;
934
935 TOKASSERT ( tokens[off] == "(" );
936 off++;
937
938 TOKASSERT ( tokens[off] != ")" );
939 while ( tokens[off] != ")" )
940 off++;
941
942 if ( tokens[off] == "{" )
943 {
944 while ( tokens[off] != "}" )
945 {
946 Type t = identify ( tokens, off );
947 off = parse_type ( t, tokens, off, names, dependencies );
948 }
949 off++;
950 }
951 return off;
952 }
953
954 int parse_do ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
955 {
956 TOKASSERT ( tokens[off] == "do" );
957 off++;
958
959 if ( tokens[off] != "{" )
960 {
961 Type t = identify ( tokens, off );
962 off = parse_type ( t, tokens, off, names, dependencies );
963 }
964 else
965 {
966 while ( tokens[off] != "}" )
967 {
968 Type t = identify ( tokens, off );
969 off = parse_type ( t, tokens, off, names, dependencies );
970 }
971 }
972
973 TOKASSERT ( tokens[off] == "while" );
974 off++;
975
976 TOKASSERT ( tokens[off] == "(" );
977 while ( tokens[off] != ")" )
978 off++;
979
980 TOKASSERT ( tokens[off] == ")" );
981 off++;
982
983 TOKASSERT ( tokens[off] == ";" );
984 off++;
985
986 return off;
987 }
988