1 %p 3000 2 3 %{ 4 5 /* $Id: lex.l,v 4.22 2011/01/02 18:31:53 tom Exp $ 6 * 7 * Lexical analyzer for C function prototype generator 8 * 9 * This is designed to parse lexically at the top level (e.g., of extern 10 * objects such as procedures). The corresponding yacc-grammar expects 11 * that curly-braces (for function bodies) are recognized as a single 12 * token, BRACES. Similarly, square-brackets and their contents are 13 * passed back as BRACKETS. 14 * 15 * Assignments at the top level are data-initialization statements. 16 * These are returned as INITIALIZER. 17 * 18 * The logic here recognizes tokens inside curly-braces, but does not 19 * pass them back to the grammar. 20 * 21 * Apollo extensions: 22 * "&" is ignored when creating lint-libraries, because we ignore 23 * expressions of all kinds. Note that function-prototypes may use "&" to 24 * denote reference-parameters. By ignoring that as well, we make the 25 * output compatible with lint (kludge). 26 * 27 * Similarly, ignore "std_$call", since it is not compatible with lint. 28 * 29 * CPP_INLINE handles a special case of the Apollo CC 6.7 compiler that 30 * uses inline attribute declarations, e.g. 31 * 32 * int foo #attribute[aligned(1)]; 33 * 34 * In CC 6.8 this behavior is hidden by a macro. 35 * 36 * VAX/VMS extensions: 37 * Treat the keywords 'globalref', etc., as 'extern'. 38 * 39 * The keywords 'noshare' and 'readonly' are type-qualifiers. 40 * 41 * GCC extensions: 42 * The keywords '__attribute__', '__inline', '__inline__', '__signed', 43 * '__signed__'. and '__extension__' 44 */ 45 46 #define result(nn) count(); if (!brackets && unnested()) return(nn) 47 48 #define is_IDENTIFIER save_text_offset();\ 49 return type_of_name(yytext); 50 51 #if !OPT_LINTLIBRARY 52 #define gcc_attribute absorb_special /* otherwise, we don't care */ 53 #endif 54 55 #ifdef apollo 56 #define apollo_keyword 57 #define apollo_special absorb_special() 58 #else 59 #define apollo_keyword is_IDENTIFIER 60 #define apollo_special is_IDENTIFIER 61 #endif 62 63 #ifdef vms 64 #define vms_extern save_text_offset(); return(T_EXTERN); 65 #define vms_keyword save_text_offset(); 66 #else /* unix */ 67 #define vms_extern is_IDENTIFIER 68 #define vms_keyword is_IDENTIFIER 69 #endif /* vms/unix */ 70 71 char *varargs_str; /* save printflike/scanflike text */ 72 int varargs_num; /* code to save "VARARGS" */ 73 int debug_trace; /* true if we trace token-level stuff */ 74 char base_file[BUFSIZ]; /* top-level file name */ 75 76 static int asm_level; /* parenthesis level for "asm" parsing */ 77 static int save_cpp; /* true if cpp-text within curly braces */ 78 static int in_cpp; /* true while we are within cpp-text */ 79 static int curly; /* number of curly brace nesting levels */ 80 static int ly_count; /* number of occurances of %% */ 81 82 #ifdef FLEX_SCANNER 83 /* flex scanner state */ 84 static YY_BUFFER_STATE *buffer_stack; 85 86 #ifdef __cplusplus 87 #define LexInput() yyinput() 88 #endif 89 90 #endif /* FLEX_SCANNER */ 91 92 #ifndef LexInput 93 #define LexInput() input() 94 #endif 95 96 static unsigned inc_limit; /* stack size */ 97 static int inc_depth; /* include nesting level */ 98 static IncludeStack *inc_stack; /* stack of included files */ 99 static SymbolTable *included_files; /* files already included */ 100 101 static int type_of_name(char *name); 102 static void startCpp(int level); 103 static void finishCpp(void); 104 #if defined(apollo) || !OPT_LINTLIBRARY 105 static void absorb_special(void); 106 #endif 107 #if OPT_LINTLIBRARY 108 static void gcc_attribute(void); 109 #endif 110 static void update_line_num(void); 111 static void save_text(void); 112 static void save_text_offset(void); 113 static void get_quoted(void); 114 static void get_comment(void); 115 static void get_cpp_directive(int copy); 116 static void parsing_file_name(unsigned need); 117 static void do_include(char *f); 118 static void include_file(char *name, int convert); 119 static void put_file(FILE *outf); 120 static void put_quoted(int c); 121 122 #if OPT_LINTLIBRARY 123 static int decipher_comment(char *keyword, int len); 124 #endif 125 126 %} 127 128 WS [ \t] 129 LETTER [A-Za-z$_] 130 DIGIT [0-9] 131 ID {LETTER}({LETTER}|{DIGIT})* 132 QUOTE [\"\'] 133 134 %s CPP1 INIT1 INIT2 CURLY LEXYACC ASM CPP_INLINE 135 %% 136 137 \n { save_text(); cur_file->line_num++; 138 cur_declarator = NULL; } 139 140 "/*" { save_text(); get_comment(); } 141 "//".*$ save_text(); 142 143 <INITIAL>"&" { save_text(); return '&'; /* C++ ref-variable? */ } 144 145 <LEXYACC>^"%%" { save_text(); if (++ly_count >= 2) BEGIN INITIAL; } 146 <LEXYACC>^"%{" { save_text(); BEGIN INITIAL; } 147 <LEXYACC>{QUOTE} get_quoted(); 148 <LEXYACC>. save_text(); 149 <INITIAL>^"%}" { save_text(); BEGIN LEXYACC; } 150 151 <INITIAL>#{WS}* { save_text(); startCpp(0); } 152 <INITIAL>"??="{WS}* { save_text(); startCpp(0); } 153 154 <CPP1>attribute { BEGIN CPP_INLINE; /* apollo */} 155 <CPP1>options { BEGIN CPP_INLINE; /* apollo */} 156 <CPP_INLINE>[^;]* finishCpp(); 157 158 <CPP1>define{WS}+{ID} { 159 char *name; 160 char *value; 161 162 save_text(); 163 164 *(name = (char *) xmalloc((size_t) (yyleng + 1))) = '\0'; 165 sscanf(yytext, "define %s", name); 166 167 get_cpp_directive(1); 168 169 *(value = (char *) xmalloc(1 + strlen(temp_buf))) = '\0'; 170 sscanf(temp_buf, "%s", value); 171 172 new_symbol(define_names, name, value, DS_NONE); 173 174 free(name); 175 free(value); 176 } 177 178 <CPP1>include{WS}* { 179 save_text(); 180 181 get_cpp_directive(1); 182 183 if (temp_buf[0] != '"' && temp_buf[0] != '<') { 184 Symbol *sym = find_symbol(define_names, temp_buf); 185 if (sym != NULL && sym->value != NULL) { 186 need_temp(strlen(sym->value)); 187 strcpy(temp_buf, sym->value); 188 } else { 189 temp_buf[0] = '\0'; 190 } 191 } 192 if (temp_buf[0] != '\0') 193 do_include(temp_buf); 194 } 195 196 <CPP1>line{WS}+[0-9]+{WS}+\".*$ { 197 save_text(); 198 199 parsing_file_name((unsigned) yyleng); 200 sscanf(yytext, "line %u \"%[^\"]\"", 201 &cur_file->line_num, 202 cur_file->file_name); 203 204 cur_file->line_num--; 205 track_in(); 206 finishCpp(); 207 } 208 <CPP1>[0-9]+{WS}+\".*$ { 209 save_text(); 210 211 parsing_file_name((unsigned) yyleng); 212 sscanf(yytext, "%u \"%[^\"]\"", 213 &cur_file->line_num, 214 cur_file->file_name); 215 216 cur_file->line_num--; 217 track_in(); 218 finishCpp(); 219 } 220 <CPP1>[0-9]+.*$ { 221 save_text(); 222 sscanf(yytext, "%u ", &cur_file->line_num); 223 cur_file->line_num--; 224 track_in(); 225 finishCpp(); 226 } 227 228 <CPP1>. { save_text(); get_cpp_directive(0); } 229 230 <INITIAL>"(" { save_text_offset(); return '('; } 231 <INITIAL>")" { 232 save_text(); 233 if (cur_file->convert) 234 cur_file->begin_comment = 235 ftell(cur_file->tmp_file); 236 return ')'; 237 } 238 <INITIAL>"*" { save_text_offset(); return '*'; } 239 <INITIAL>[,;] { 240 save_text(); 241 if (cur_file->convert) 242 cur_file->begin_comment = 243 ftell(cur_file->tmp_file); 244 return yytext[0]; 245 } 246 <INITIAL>"..." { save_text(); return T_ELLIPSIS; } 247 <INITIAL>\" { 248 get_quoted(); 249 return T_STRING_LITERAL; 250 } 251 252 <INITIAL>"__asm__" { save_text(); BEGIN ASM; return T_ASM; } 253 <INITIAL>asm { save_text(); BEGIN ASM; return T_ASM; } 254 <ASM>"(" { ++asm_level; save_text(); } 255 <ASM>")" { --asm_level; save_text(); if (asm_level <= 0) { asm_level = 0; BEGIN INITIAL; return T_ASMARG; } } 256 <ASM>{QUOTE} get_quoted(); 257 <ASM>. save_text(); 258 259 <INITIAL>__?based[^(]*\([^)]*\) { save_text_offset(); return T_TYPE_QUALIFIER; } 260 261 <INITIAL>auto { save_text_offset(); return T_AUTO; } 262 <INITIAL>extern { save_text_offset(); return T_EXTERN; } 263 <INITIAL>register { save_text_offset(); return T_REGISTER; } 264 <INITIAL>static { save_text_offset(); return T_STATIC; } 265 <INITIAL>typedef { save_text_offset(); return T_TYPEDEF; } 266 <INITIAL>inline { save_text_offset(); return T_INLINE; } 267 268 <INITIAL>_Bool { save_text_offset(); return T_Bool; } 269 <INITIAL>_Complex { save_text_offset(); return T_Complex; } 270 <INITIAL>_Imaginary { save_text_offset(); return T_Imaginary; } 271 272 <INITIAL>char { save_text_offset(); return T_CHAR; } 273 <INITIAL>double { save_text_offset(); return T_DOUBLE; } 274 <INITIAL>float { save_text_offset(); return T_FLOAT; } 275 <INITIAL>int { save_text_offset(); return T_INT; } 276 <INITIAL>void { save_text_offset(); return T_VOID; } 277 <INITIAL>long { save_text_offset(); return T_LONG; } 278 <INITIAL>short { save_text_offset(); return T_SHORT; } 279 <INITIAL>signed { save_text_offset(); return T_SIGNED; } 280 <INITIAL>unsigned { save_text_offset(); return T_UNSIGNED; } 281 282 <INITIAL>enum { save_text_offset(); return T_ENUM; } 283 <INITIAL>struct { save_text_offset(); return T_STRUCT; } 284 <INITIAL>union { save_text_offset(); return T_UNION; } 285 <INITIAL>va_dcl { save_text_offset(); return T_VA_DCL; } 286 287 <INITIAL>__signed { save_text_offset(); return T_SIGNED; } 288 <INITIAL>__signed__ { save_text_offset(); return T_SIGNED; } 289 <INITIAL>__inline { save_text_offset(); return T_INLINE; } 290 <INITIAL>__inline__ { save_text_offset(); return T_INLINE; } 291 <INITIAL>__extension__ { save_text_offset(); return T_EXTENSION; } 292 <INITIAL>__attribute__ { gcc_attribute(); } 293 294 <INITIAL>globalvalue { vms_extern; } 295 <INITIAL>globalref { vms_extern; } 296 <INITIAL>globaldef { vms_extern; } 297 298 <INITIAL>"std_$call" { apollo_keyword; } 299 <INITIAL>"__attribute" { apollo_special; } 300 301 <INITIAL>{ID} { is_IDENTIFIER } 302 303 <INITIAL>\[[^\]]*\] { 304 /* This can't handle the case where a comment 305 * containing a ] appears between the brackets. 306 */ 307 save_text_offset(); 308 update_line_num(); 309 return T_BRACKETS; 310 } 311 <INITIAL>"??("[^?]*"??)" { 312 save_text_offset(); 313 update_line_num(); 314 return T_BRACKETS; 315 } 316 317 <INITIAL>"=" { save_text(); BEGIN INIT1; return '='; } 318 <INIT1>"{" { save_text(); curly = 1; BEGIN INIT2; } 319 <INIT1>[,;] { 320 unput(yytext[yyleng-1]); 321 BEGIN INITIAL; 322 return T_INITIALIZER; 323 } 324 <INIT1>{QUOTE} get_quoted(); 325 <INIT1>. save_text(); 326 327 <INIT2>"{" { save_text(); ++curly; } 328 <INIT2>"}" { 329 save_text(); 330 if (--curly == 0) { 331 BEGIN INITIAL; 332 return T_INITIALIZER; 333 } 334 } 335 <INIT2>{QUOTE} get_quoted(); 336 <INIT2>. save_text(); 337 338 <INITIAL>"{" { 339 save_text(); 340 curly = 1; 341 return_val = 342 returned_at = FALSE; 343 BEGIN CURLY; 344 return T_LBRACE; 345 } 346 <CURLY>"{" { save_text(); ++curly; } 347 <CURLY>"}" { 348 save_text(); 349 if (--curly == 0) { 350 BEGIN INITIAL; 351 return T_MATCHRBRACE; 352 } 353 } 354 <CURLY>{QUOTE} get_quoted(); 355 <CURLY>"return" { save_text(); returned_at = TRUE; } 356 <CURLY>";" { save_text(); returned_at = FALSE; } 357 <CURLY>#{WS}* { save_text(); startCpp(1); } 358 <CURLY>"??="{WS}* { save_text(); startCpp(1); } 359 <CURLY>. { save_text(); return_val |= returned_at; } 360 361 [ \r\t\f]+ save_text(); 362 . { 363 save_text(); 364 put_error(); 365 fprintf(stderr, "bad character '%c'\n", yytext[0]); 366 } 367 %% 368 369 static void 370 startCpp(int level) 371 { 372 save_cpp = level; 373 in_cpp = TRUE; 374 BEGIN CPP1; 375 } 376 377 static void 378 finishCpp(void) 379 { 380 in_cpp = FALSE; 381 if (save_cpp) 382 BEGIN CURLY; 383 else 384 BEGIN INITIAL; 385 } 386 387 /* 388 * Skip over embedded __attribute/__attribute_ syntax. 389 */ 390 #if defined(apollo) || !OPT_LINTLIBRARY 391 static void 392 absorb_special(void) 393 { 394 int c; 395 int nest = 0; 396 while ((c = input()) > 0) { 397 if (c == '(') 398 nest++; 399 else if (c == ')') { 400 if (--nest <= 0) 401 break; 402 } 403 } 404 } 405 #endif 406 407 #if OPT_LINTLIBRARY 408 /* 409 * This recognizes some of the special attribute macros defined by gcc: 410 * noreturn 411 * format(printf,n,m) 412 * format(scanf,n,m) 413 * and uses that information to construct equivalent lint-library text. 414 * (It's a distinct piece of code from the 'absorb_special()' function to 415 * avoid spurious matches with non-gcc compilers). 416 */ 417 static void 418 gcc_attribute(void) 419 { 420 int c, num1, num2; 421 int nest = 0; 422 unsigned len = 0; 423 char bfr[BUFSIZ]; 424 425 while ((c = LexInput()) > 0) { 426 if (len < sizeof(bfr) - 1 && !isspace(c)) 427 bfr[len++] = (char) c; 428 if (c == '(') 429 nest++; 430 else if (c == ')') { 431 if (--nest <= 0) 432 break; 433 } 434 } 435 bfr[len] = '\0'; 436 if (!strcmp(bfr, "((noreturn))")) { 437 exitlike_func = TRUE; 438 } else if (sscanf(bfr, "((format(printf,%d,%d)))", &num1, &num2) == 2) { 439 (void) sprintf(bfr, "PRINTFLIKE%d", varargs_num = num1); 440 varargs_str = xstrdup(bfr); 441 } else if (sscanf(bfr, "((format(scanf,%d,%d)))", &num1, &num2) == 2) { 442 (void) sprintf(bfr, "SCANFLIKE%d", varargs_num = num1); 443 varargs_str = xstrdup(bfr); 444 } 445 } 446 #endif 447 448 /* Decode the current token according to the type-of-name 449 */ 450 static int 451 type_of_name(char *name) 452 { 453 if (find_symbol(type_qualifiers, name) != NULL) 454 return T_TYPE_QUALIFIER; 455 else if (find_symbol(typedef_names, name) != NULL) 456 return T_TYPEDEF_NAME; 457 else if (find_symbol(define_names, name) != NULL) 458 return T_DEFINE_NAME; 459 else 460 return T_IDENTIFIER; 461 } 462 463 boolean 464 is_typedef_name(char *name) 465 { 466 return (boolean) (find_symbol(typedef_names, name) != NULL); 467 } 468 469 /* If the matched text contains any new line characters, then update the 470 * current line number. 471 */ 472 static void 473 update_line_num(void) 474 { 475 char *p = yytext; 476 while (*p != '\0') { 477 if (*p++ == '\n') 478 cur_file->line_num++; 479 } 480 } 481 482 /* Save the matched text in the temporary file. 483 */ 484 static void 485 save_text(void) 486 { 487 #if OPT_LINTLIBRARY 488 if (!in_cpp) 489 copy_typedef(yytext); 490 #endif 491 if (cur_file->convert) { 492 fputs(yytext, cur_file->tmp_file); 493 } 494 } 495 496 /* Record the current position in the temporary file and write the matched text 497 * to the file. 498 */ 499 static void 500 save_text_offset(void) 501 { 502 (void) strcpy(yylval.text.text, yytext); 503 #if OPT_LINTLIBRARY 504 copy_typedef(yytext); 505 #endif 506 if (cur_file->convert) { 507 yylval.text.begin = ftell(cur_file->tmp_file); 508 fputs(yytext, cur_file->tmp_file); 509 } else 510 yylval.text.begin = 0; 511 } 512 513 #if OPT_LINTLIBRARY 514 /* Decipher comments that are useful for lint (and making lint-libraries) 515 */ 516 static struct { 517 int varText; 518 int varargs; 519 int externs; 520 int preproz; 521 } cmtVal; 522 523 static int 524 decipher_comment(char *keyword, int len) 525 { 526 if (len != 0) { 527 int value; 528 keyword[len] = '\0'; 529 530 /* these are recognized by some lint-programs */ 531 if (!strcmp(keyword, "VARARGS")) { 532 cmtVal.varargs = -1; 533 } else if (sscanf(keyword, "VARARGS%d", &value) == 1) { 534 cmtVal.varargs = value; 535 } else if (!strcmp(keyword, "PRINTFLIKE")) { 536 cmtVal.varargs = 1; 537 cmtVal.varText = TRUE; 538 } else if (sscanf(keyword, "PRINTFLIKE%d", &value) == 1) { 539 cmtVal.varargs = value; 540 cmtVal.varText = TRUE; 541 } else if (!strcmp(keyword, "SCANFLIKE")) { 542 cmtVal.varargs = 2; 543 cmtVal.varText = TRUE; 544 } else if (sscanf(keyword, "SCANFLIKE%d", &value) == 1) { 545 cmtVal.varargs = value; 546 cmtVal.varText = TRUE; 547 /* these are extensions added to simplify library-generation */ 548 } else if (!strcmp(keyword, "LINT_EXTERN")) { 549 cmtVal.externs = MAX_INC_DEPTH; 550 } else if (sscanf(keyword, "LINT_EXTERN%d", &value) == 1) { 551 cmtVal.externs = value; 552 } else if (!strcmp(keyword, "LINT_PREPRO")) { 553 cmtVal.preproz = -1; /* the whole comment */ 554 } else if (sscanf(keyword, "LINT_PREPRO%d", &value) == 1) { 555 cmtVal.preproz = value; 556 } else if (!strcmp(keyword, "LINT_SHADOWED")) { 557 lint_shadowed = TRUE; 558 } 559 } 560 return 0; 561 } 562 #endif 563 564 static void 565 put_quoted(int c) 566 { 567 /* Modifying 'yytext[]' doesn't work well with FLEX, which simply 568 * maintains 'yytext' as a pointer into its input buffer. LEX copies 569 * characters into the 'yytext[]' array. 570 */ 571 #if defined(FLEX_SCANNER) || !defined(YYLMAX) 572 if (c != 0) { 573 static char temp[2]; 574 temp[0] = (char) c; 575 /* save_text */ 576 # if OPT_LINTLIBRARY 577 if (!in_cpp) 578 copy_typedef(temp); 579 # endif 580 if (cur_file->convert) { 581 fputs(temp, cur_file->tmp_file); 582 } 583 /* update_line_num */ 584 if (c == '\n') 585 cur_file->line_num++; 586 } 587 #else /* this works fine on LEX (e.g., on SunOS 4.x) */ 588 589 if ((c == 0) || (yyleng + 1 >= YYLMAX)) { 590 save_text(); 591 update_line_num(); 592 yyleng = 0; 593 } 594 if (c != 0) { 595 yytext[yyleng++] = c; 596 yytext[yyleng] = 0; 597 } 598 #endif /* LEX/FLEX */ 599 } 600 601 /* 602 * Scan past the characters in a backslash sequence 603 */ 604 /* Scan past quoted string. Note that some strings may overflow 'yytext[]', so 605 * we don't try to eat them in the lexical rules. 606 */ 607 static void 608 get_quoted(void) 609 { 610 int delim = *yytext; 611 int c; 612 613 #if defined(FLEX_SCANNER) || !defined(YYLMAX) 614 put_quoted(delim); 615 #endif 616 while ((c = LexInput()) != 0) { 617 if (c == '\\') { 618 put_quoted(c); 619 if ((c = LexInput()) == 0) 620 break; 621 put_quoted(c); 622 } else { 623 put_quoted(c); 624 if (c == delim) 625 break; 626 if (c == '\n') { /* recover from unbalanced */ 627 put_error(); 628 fprintf(stderr, "unbalanced quote character '%c'\n", delim); 629 break; 630 } 631 } 632 } 633 put_quoted(0); 634 } 635 636 /* Scan to end of comment. 637 */ 638 static void 639 get_comment(void) 640 { 641 int c, lastc = '\0'; 642 643 #if OPT_LINTLIBRARY 644 unsigned len = 0; 645 char keyword[BUFSIZ]; 646 647 keyword[len] = '\0'; 648 cmtVal.varText = 0; 649 cmtVal.varargs = 0; 650 cmtVal.externs = -1; 651 cmtVal.preproz = 0; 652 #endif 653 654 while ((c = LexInput()) != 0) { 655 if (cur_file->convert) 656 fputc(c, cur_file->tmp_file); 657 658 #if OPT_LINTLIBRARY 659 if (!(isalnum(c) || c == '_' || c == '$')) { 660 int flag = cmtVal.preproz; 661 len = (unsigned) decipher_comment(keyword, (int) len); 662 if (flag != cmtVal.preproz) 663 lastc = '\0'; 664 } else if (len + 1 < sizeof(keyword)) { 665 keyword[len++] = (char) c; 666 } 667 #endif 668 669 switch (c) { 670 case '\n': 671 cur_file->line_num++; 672 #if OPT_LINTLIBRARY 673 if (cmtVal.preproz != 0 && lastc != '\0') 674 fputc(lastc, stdout); 675 if (cmtVal.preproz > 0) /* if negative, we pass everything */ 676 cmtVal.preproz -= 1; 677 #endif 678 break; 679 case '/': 680 if (lastc == '*') { 681 if (cur_file->convert) { 682 if (func_params && cur_declarator) { 683 cur_declarator->begin_comment = cur_file->begin_comment; 684 cur_file->begin_comment = ftell(cur_file->tmp_file); 685 cur_declarator->end_comment = cur_file->begin_comment; 686 cur_declarator = NULL; 687 } else { 688 cur_file->end_comment = ftell(cur_file->tmp_file); 689 } 690 } 691 #if OPT_LINTLIBRARY 692 (void) decipher_comment(keyword, (int) len); 693 if (cmtVal.varargs != 0) { 694 if ((varargs_num = cmtVal.varargs) != 0 695 && cmtVal.varText != 0) { 696 if (varargs_str != 0) 697 free(varargs_str); 698 varargs_str = xstrdup(keyword); 699 } 700 } 701 if (cmtVal.externs >= 0) 702 extern_in = (unsigned) cmtVal.externs; 703 if (cmtVal.preproz != 0) 704 fputc('\n', stdout); 705 #endif 706 return; 707 } 708 /* FALLTHRU */ 709 default: 710 #if OPT_LINTLIBRARY 711 if (cmtVal.preproz != 0 && lastc != '\0') 712 fputc(lastc, stdout); 713 #endif 714 break; 715 } 716 lastc = c; 717 } 718 } 719 720 /* Scan rest of preprocessor directive. If copy is true, then store the text 721 * in temp_buf. 722 */ 723 static void 724 get_cpp_directive(int copy) 725 { 726 unsigned used = 0; 727 char c, lastc[4]; 728 729 lastc[0] = lastc[1] = lastc[2] = lastc[3] = '\0'; 730 if (copy) { 731 need_temp((size_t) 2); 732 *temp_buf = '\0'; 733 } 734 735 while ((c = (char) LexInput()) != 0) { 736 if (cur_file->convert) 737 fputc(c, cur_file->tmp_file); 738 739 switch (c) { 740 case '\n': 741 cur_file->line_num++; 742 if (lastc[2] != '\\' && strcmp(lastc, "?\?/") != 0) { 743 finishCpp(); 744 return; 745 } 746 break; 747 case '*': 748 if (lastc[2] == '/') 749 get_comment(); 750 break; 751 } 752 lastc[0] = lastc[1]; 753 lastc[1] = lastc[2]; 754 lastc[2] = c; 755 756 if (copy) { 757 if (used + 2 >= temp_len) 758 need_temp(temp_len + MAX_TEXT_SIZE); 759 temp_buf[used++] = c; 760 temp_buf[used] = '\0'; 761 } 762 } 763 } 764 765 /* 766 * Ensure that the filename buffer is large enough to hold yytext, e.g., if 767 * the sscanf gave the whole buffer. 768 */ 769 static void 770 parsing_file_name(unsigned need) 771 { 772 need += 2; 773 if (cur_file->len_file_name < need) { 774 cur_file->len_file_name += need; 775 cur_file->file_name = (char *) xrealloc(cur_file->file_name, cur_file->len_file_name); 776 } 777 cur_file->file_name[0] = 0; 778 } 779 780 /* Return a pointer to the current file name. 781 */ 782 char * 783 cur_file_name(void) 784 { 785 return cur_file->file_name; 786 } 787 788 /* Return the current line number. 789 */ 790 unsigned 791 cur_line_num(void) 792 { 793 return cur_file->line_num; 794 } 795 796 /* Return the current temporary output file. 797 */ 798 FILE * 799 cur_tmp_file(void) 800 { 801 return cur_file->tmp_file; 802 } 803 804 /* Set the modify flag for the current file. 805 */ 806 void 807 cur_file_changed(void) 808 { 809 cur_file->changed = TRUE; 810 } 811 812 /* Return the temporary file offset of beginning of the current comment. 813 */ 814 long 815 cur_begin_comment(void) 816 { 817 return cur_file->begin_comment; 818 } 819 820 /* Return the text of the current lexical token. 821 */ 822 char * 823 cur_text(void) 824 { 825 return yytext; 826 } 827 828 #if !HAVE_TMPFILE 829 /* 830 * tmpfile() - return a FILE* for a temporary file that will be 831 * removed automatically when the program exits. 832 * 833 * Not all systems have the ANSI tmpfile() function yet... 834 * 835 * David W. Sanderson (dws@cs.wisc.edu) 836 * 837 * note - this was in version 3.10 from 1993 - TD 838 */ 839 FILE * 840 tmpfile(void) 841 { 842 char *name; 843 char *tmpdir; 844 FILE *f; 845 846 if ((tmpdir = getenv("TMPDIR")) == (char *) 0) { 847 tmpdir = "/tmp"; 848 } 849 name = xmalloc(strlen(tmpdir) + 20); 850 sprintf(name, "%s/TfXXXXXX", tmpdir); 851 call_mktemp(name); 852 853 if ((f = fopen(name, "w+")) != 0) { 854 if (unlink(name) == -1) { 855 fclose(f); 856 f = 0; 857 } 858 } 859 free(name); 860 return f; 861 } 862 #endif /* !HAVE_TMPFILE */ 863 864 /* Push a file onto the include stack. The stream yyin must already 865 * point to the file. 866 */ 867 static void 868 include_file(char *name, /* file name */ 869 int convert) /* if TRUE, convert function definitions */ 870 { 871 if (++inc_depth >= (int) inc_limit) { 872 unsigned need = (inc_limit | 31) + 1; 873 #ifdef FLEX_SCANNER 874 buffer_stack = type_realloc(YY_BUFFER_STATE, buffer_stack, need); 875 #endif 876 inc_stack = type_realloc(IncludeStack, inc_stack, need); 877 while (inc_limit < need) { 878 #ifdef FLEX_SCANNER 879 buffer_stack[inc_limit] = 0; 880 #endif 881 memset(inc_stack + inc_limit, 0, sizeof(*inc_stack)); 882 ++inc_limit; 883 } 884 } 885 886 cur_file = inc_stack + inc_depth; 887 cur_file->file = yyin; 888 cur_file->base_name = xstrdup(name); 889 cur_file->len_file_name = strlen(name) + MAX_TEXT_SIZE; 890 cur_file->file_name = strcpy((char *) xmalloc(cur_file->len_file_name), name); 891 cur_file->line_num = 1; 892 cur_file->convert = (boolean) convert; 893 cur_file->changed = FALSE; 894 895 #ifdef FLEX_SCANNER 896 buffer_stack[inc_depth] = yy_create_buffer(yyin, YY_BUF_SIZE); 897 yy_switch_to_buffer(buffer_stack[inc_depth]); 898 #endif 899 900 if (convert) { 901 cur_file->begin_comment = cur_file->end_comment = 0; 902 cur_file->tmp_file = tmpfile(); 903 if (cur_file->tmp_file == NULL) { 904 fprintf(stderr, "%s: cannot create temporary file\n", progname); 905 cur_file->convert = FALSE; 906 } 907 } 908 } 909 910 #define BLOCK_SIZE 2048 911 912 /* Copy converted C source from the temporary file to the output stream. 913 */ 914 static void 915 put_file(FILE *outf) 916 { 917 char block[BLOCK_SIZE]; 918 long filesize; 919 size_t nread, count; 920 921 filesize = ftell(cur_file->tmp_file); 922 fseek(cur_file->tmp_file, 0L, 0); 923 while (filesize > 0) { 924 count = (filesize < BLOCK_SIZE) ? (size_t) filesize : BLOCK_SIZE; 925 nread = fread(block, sizeof(char), count, cur_file->tmp_file); 926 if (nread == 0) 927 break; 928 fwrite(block, sizeof(char), nread, outf); 929 filesize -= (long) nread; 930 } 931 } 932 933 /* Remove the top of the include stack. 934 */ 935 void 936 pop_file(int closed) 937 { 938 FILE *outf; 939 940 if (!closed && (yyin != stdin)) 941 fclose(yyin); 942 943 if (cur_file->convert) { 944 if (yyin == stdin) { 945 put_file(stdout); 946 } else if (cur_file->changed) { 947 if ((outf = fopen(cur_file->base_name, "w")) != NULL) { 948 put_file(outf); 949 fclose(outf); 950 } else { 951 fprintf(stderr, "%s: cannot create file %s\n", progname, 952 cur_file->base_name); 953 } 954 } 955 956 fclose(cur_file->tmp_file); 957 } 958 free(cur_file->base_name); 959 free(cur_file->file_name); 960 961 #ifdef FLEX_SCANNER 962 yy_delete_buffer(YY_CURRENT_BUFFER); 963 #endif 964 965 if (--inc_depth >= 0) { 966 cur_file = inc_stack + inc_depth; 967 yyin = cur_file->file; 968 969 #ifdef FLEX_SCANNER 970 yy_switch_to_buffer(buffer_stack[inc_depth]); 971 #endif 972 } 973 } 974 975 /* Process include directive. 976 */ 977 static void 978 do_include(char *file_spec) /* path surrounded by "" or <> */ 979 { 980 unsigned stdinc; /* 1 = path surrounded by <> */ 981 char *file; 982 char *path; 983 char match, *s; 984 unsigned i; 985 unsigned n; 986 FILE *fp; 987 988 if (file_spec[0] == '"') { 989 match = '"'; 990 stdinc = 0; 991 } else if (file_spec[0] == '<') { 992 match = '>'; 993 stdinc = 1; 994 } else { 995 return; 996 } 997 s = strchr(file_spec + 1, match); 998 n = (s != NULL) ? (unsigned) (s - file_spec - 1) : 0; 999 file = xstrdup(file_spec + 1); 1000 file[n] = '\0'; 1001 1002 /* Do nothing if the file was already included. */ 1003 path = (char *) xmalloc(strlen(file) + 3); 1004 sprintf(path, stdinc ? "<%s>" : "\"%s\"", file); 1005 if (find_symbol(included_files, path) == NULL) { 1006 new_symbol(included_files, path, NULL, DS_NONE); 1007 1008 for (i = (unsigned) (stdinc != 0); i < num_inc_dir; ++i) { 1009 if (strlen(inc_dir[i]) == 0 || !strcmp(inc_dir[i], CURRENT_DIR)) { 1010 strcpy(path, file); 1011 } else { 1012 path = (char *) xrealloc(path, strlen(file) + 1013 strlen(inc_dir[i]) + 2); 1014 sprintf(path, "%s/%s", inc_dir[i], file); 1015 } 1016 if ((fp = fopen(path, "r")) != NULL) { 1017 yyin = fp; 1018 include_file(path, func_style != FUNC_NONE && !stdinc); 1019 free(file); 1020 free(path); 1021 return; 1022 } 1023 } 1024 1025 if (!quiet) { 1026 put_error(); 1027 fprintf(stderr, "cannot read file %s\n", file_spec); 1028 } 1029 } 1030 free(file); 1031 free(path); 1032 } 1033 1034 /* When the end of the current input file is reached, pop a 1035 * nested include file. 1036 */ 1037 int 1038 yywrap(void) 1039 { 1040 if (inc_depth > 0) { 1041 pop_file(FALSE); 1042 return 0; 1043 } else { 1044 return 1; 1045 } 1046 } 1047 1048 #ifdef NO_LEAKS 1049 void 1050 free_lexer(void) 1051 { 1052 if (inc_limit != 0) { 1053 #ifdef FLEX_SCANNER 1054 free(buffer_stack); 1055 #endif 1056 free(inc_stack); 1057 } 1058 } 1059 #endif 1060