Reactos
at listview 988 lines 23 kB view raw
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) \ 27if(!(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} 36using std::string; 37using std::vector; 38 39vector<Header*> headers; 40 41bool import_file ( const char* filename ); 42char* findend ( char* p, bool& externc ); 43Type identify ( const vector<string>& tokens, int off = 0 ); 44Type process ( const string& element, vector<string>& names, bool& isTypedef, vector<string>& dependencies ); 45void process_preprocessor ( const char* filename, Header& h, const string& element ); 46void process_c ( Header& h, const string& element ); 47int parse_type ( Type t, const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 48int parse_ignored_statement ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 49int parse_tident ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 50int parse_variable ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 51int parse_struct ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 52int parse_function ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 53int parse_function_ptr ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 54int parse_ifwhile ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 55int parse_do ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies ); 56 57const 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 70bool 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 82BOOL 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 89void 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 114bool 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 193string 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 211void 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 387void 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 428char* 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 453char* 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 550int 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 570Type 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 628Type 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 653int 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 680void 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 694void 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 708int 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 717int 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 726int 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 739int 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 796int 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 830int 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 896int 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 930int 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 954int 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