1 /****************************************************************************** 2 * 3 * Module Name: prscan - Preprocessor start-up and file scan module 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #define _DECLARE_PR_GLOBALS 45 46 #include "aslcompiler.h" 47 #include "dtcompiler.h" 48 49 /* 50 * TBDs: 51 * 52 * No nested macros, maybe never 53 * Implement ASL "Include" as well as "#include" here? 54 */ 55 #define _COMPONENT ASL_PREPROCESSOR 56 ACPI_MODULE_NAME ("prscan") 57 58 59 /* Local prototypes */ 60 61 static void 62 PrPreprocessInputFile ( 63 void); 64 65 static void 66 PrDoDirective ( 67 char *DirectiveToken, 68 char **Next); 69 70 static void 71 PrGetNextLineInit ( 72 void); 73 74 static UINT32 75 PrGetNextLine ( 76 FILE *Handle); 77 78 static int 79 PrMatchDirective ( 80 char *Directive); 81 82 static void 83 PrPushDirective ( 84 int Directive, 85 char *Argument); 86 87 static ACPI_STATUS 88 PrPopDirective ( 89 void); 90 91 static void 92 PrDbgPrint ( 93 char *Action, 94 char *DirectiveName); 95 96 static void 97 PrDoIncludeBuffer ( 98 char *Pathname, 99 char *BufferName); 100 101 static void 102 PrDoIncludeFile ( 103 char *Pathname); 104 105 106 /* 107 * Supported preprocessor directives 108 * Each entry is of the form "Name, ArgumentCount" 109 */ 110 static const PR_DIRECTIVE_INFO Gbl_DirectiveInfo[] = 111 { 112 {"define", 1}, 113 {"elif", 0}, /* Converted to #else..#if internally */ 114 {"else", 0}, 115 {"endif", 0}, 116 {"error", 1}, 117 {"if", 1}, 118 {"ifdef", 1}, 119 {"ifndef", 1}, 120 {"include", 0}, /* Argument is not standard format, so just use 0 here */ 121 {"includebuffer", 0}, /* Argument is not standard format, so just use 0 here */ 122 {"line", 1}, 123 {"pragma", 1}, 124 {"undef", 1}, 125 {"warning", 1}, 126 {NULL, 0} 127 }; 128 129 /* This table must match ordering of above table exactly */ 130 131 enum Gbl_DirectiveIndexes 132 { 133 PR_DIRECTIVE_DEFINE = 0, 134 PR_DIRECTIVE_ELIF, 135 PR_DIRECTIVE_ELSE, 136 PR_DIRECTIVE_ENDIF, 137 PR_DIRECTIVE_ERROR, 138 PR_DIRECTIVE_IF, 139 PR_DIRECTIVE_IFDEF, 140 PR_DIRECTIVE_IFNDEF, 141 PR_DIRECTIVE_INCLUDE, 142 PR_DIRECTIVE_INCLUDEBUFFER, 143 PR_DIRECTIVE_LINE, 144 PR_DIRECTIVE_PRAGMA, 145 PR_DIRECTIVE_UNDEF, 146 PR_DIRECTIVE_WARNING 147 }; 148 149 #define ASL_DIRECTIVE_NOT_FOUND -1 150 151 152 /******************************************************************************* 153 * 154 * FUNCTION: PrInitializePreprocessor 155 * 156 * PARAMETERS: None 157 * 158 * RETURN: None 159 * 160 * DESCRIPTION: Startup initialization for the Preprocessor. 161 * 162 ******************************************************************************/ 163 164 void 165 PrInitializePreprocessor ( 166 void) 167 { 168 /* Init globals and the list of #defines */ 169 170 PrInitializeGlobals (); 171 Gbl_DefineList = NULL; 172 } 173 174 175 /******************************************************************************* 176 * 177 * FUNCTION: PrInitializeGlobals 178 * 179 * PARAMETERS: None 180 * 181 * RETURN: None 182 * 183 * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup 184 * initialization and re-initialization between compiles during 185 * a multiple source file compile. 186 * 187 ******************************************************************************/ 188 189 void 190 PrInitializeGlobals ( 191 void) 192 { 193 /* Init globals */ 194 195 Gbl_InputFileList = NULL; 196 Gbl_CurrentLineNumber = 1; 197 Gbl_PreprocessorLineNumber = 1; 198 Gbl_PreprocessorError = FALSE; 199 200 /* These are used to track #if/#else blocks (possibly nested) */ 201 202 Gbl_IfDepth = 0; 203 Gbl_IgnoringThisCodeBlock = FALSE; 204 Gbl_DirectiveStack = NULL; 205 } 206 207 208 /******************************************************************************* 209 * 210 * FUNCTION: PrTerminatePreprocessor 211 * 212 * PARAMETERS: None 213 * 214 * RETURN: None 215 * 216 * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any 217 * defines that were specified on the command line, in order to 218 * support multiple compiles with a single compiler invocation. 219 * 220 ******************************************************************************/ 221 222 void 223 PrTerminatePreprocessor ( 224 void) 225 { 226 PR_DEFINE_INFO *DefineInfo; 227 228 229 /* 230 * The persistent defines (created on the command line) are always at the 231 * end of the list. We save them. 232 */ 233 while ((Gbl_DefineList) && (!Gbl_DefineList->Persist)) 234 { 235 DefineInfo = Gbl_DefineList; 236 Gbl_DefineList = DefineInfo->Next; 237 238 ACPI_FREE (DefineInfo->Replacement); 239 ACPI_FREE (DefineInfo->Identifier); 240 ACPI_FREE (DefineInfo); 241 } 242 } 243 244 245 /******************************************************************************* 246 * 247 * FUNCTION: PrDoPreprocess 248 * 249 * PARAMETERS: None 250 * 251 * RETURN: None 252 * 253 * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must 254 * be already open. Handles multiple input files via the 255 * #include directive. 256 * 257 ******************************************************************************/ 258 259 void 260 PrDoPreprocess ( 261 void) 262 { 263 BOOLEAN MoreInputFiles; 264 265 266 DbgPrint (ASL_DEBUG_OUTPUT, "Starting preprocessing phase\n\n"); 267 268 269 FlSeekFile (ASL_FILE_INPUT, 0); 270 PrDumpPredefinedNames (); 271 272 /* Main preprocessor loop, handles include files */ 273 274 do 275 { 276 PrPreprocessInputFile (); 277 MoreInputFiles = PrPopInputFileStack (); 278 279 } while (MoreInputFiles); 280 281 /* Point compiler input to the new preprocessor output file (.pre) */ 282 283 FlCloseFile (ASL_FILE_INPUT); 284 Gbl_Files[ASL_FILE_INPUT].Handle = Gbl_Files[ASL_FILE_PREPROCESSOR].Handle; 285 AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle; 286 287 /* Reset globals to allow compiler to run */ 288 289 FlSeekFile (ASL_FILE_INPUT, 0); 290 if (!Gbl_PreprocessOnly) 291 { 292 Gbl_CurrentLineNumber = 0; 293 } 294 295 DbgPrint (ASL_DEBUG_OUTPUT, "Preprocessing phase complete \n\n"); 296 } 297 298 299 /******************************************************************************* 300 * 301 * FUNCTION: PrPreprocessInputFile 302 * 303 * PARAMETERS: None 304 * 305 * RETURN: None 306 * 307 * DESCRIPTION: Preprocess one entire file, line-by-line. 308 * 309 * Input: Raw user ASL from ASL_FILE_INPUT 310 * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR and 311 * (optionally) ASL_FILE_PREPROCESSOR_USER 312 * 313 ******************************************************************************/ 314 315 static void 316 PrPreprocessInputFile ( 317 void) 318 { 319 UINT32 Status; 320 char *Token; 321 char *ReplaceString; 322 PR_DEFINE_INFO *DefineInfo; 323 ACPI_SIZE TokenOffset; 324 char *Next; 325 int OffsetAdjust; 326 327 328 PrGetNextLineInit (); 329 330 /* Scan source line-by-line and process directives. Then write the .i file */ 331 332 while ((Status = PrGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF) 333 { 334 Gbl_CurrentLineNumber++; 335 Gbl_LogicalLineNumber++; 336 337 if ((Status == ASL_WITHIN_COMMENT) || 338 (Status == ASL_BLANK_LINE)) 339 { 340 goto WriteEntireLine; 341 } 342 343 /* Need a copy of the input line for strok() */ 344 345 strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer); 346 Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next); 347 OffsetAdjust = 0; 348 349 /* All preprocessor directives must begin with '#' */ 350 351 if (Token && (*Token == '#')) 352 { 353 if (strlen (Token) == 1) 354 { 355 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next); 356 } 357 else 358 { 359 Token++; /* Skip leading # */ 360 } 361 362 /* Execute the directive, do not write line to output file */ 363 364 PrDoDirective (Token, &Next); 365 continue; 366 } 367 368 /* 369 * If we are currently within the part of an IF/ELSE block that is 370 * FALSE, ignore the line and do not write it to the output file. 371 * This continues until an #else or #endif is encountered. 372 */ 373 if (Gbl_IgnoringThisCodeBlock) 374 { 375 continue; 376 } 377 378 /* Match and replace all #defined names within this source line */ 379 380 while (Token) 381 { 382 DefineInfo = PrMatchDefine (Token); 383 if (DefineInfo) 384 { 385 if (DefineInfo->Body) 386 { 387 /* This is a macro */ 388 389 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 390 "Matched Macro: %s->%s\n", 391 Gbl_CurrentLineNumber, DefineInfo->Identifier, 392 DefineInfo->Replacement); 393 394 PrDoMacroInvocation (Gbl_MainTokenBuffer, Token, 395 DefineInfo, &Next); 396 } 397 else 398 { 399 ReplaceString = DefineInfo->Replacement; 400 401 /* Replace the name in the original line buffer */ 402 403 TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust; 404 PrReplaceData ( 405 &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token), 406 ReplaceString, strlen (ReplaceString)); 407 408 /* Adjust for length difference between old and new name length */ 409 410 OffsetAdjust += strlen (ReplaceString) - strlen (Token); 411 412 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 413 "Matched #define: %s->%s\n", 414 Gbl_CurrentLineNumber, Token, 415 *ReplaceString ? ReplaceString : "(NULL STRING)"); 416 } 417 } 418 419 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next); 420 } 421 422 Gbl_PreprocessorLineNumber++; 423 424 425 WriteEntireLine: 426 /* 427 * Now we can write the possibly modified source line to the 428 * preprocessor file(s). 429 */ 430 FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer, 431 strlen (Gbl_CurrentLineBuffer)); 432 } 433 } 434 435 436 /******************************************************************************* 437 * 438 * FUNCTION: PrDoDirective 439 * 440 * PARAMETERS: Directive - Pointer to directive name token 441 * Next - "Next" buffer from GetNextToken 442 * 443 * RETURN: None. 444 * 445 * DESCRIPTION: Main processing for all preprocessor directives 446 * 447 ******************************************************************************/ 448 449 static void 450 PrDoDirective ( 451 char *DirectiveToken, 452 char **Next) 453 { 454 char *Token = Gbl_MainTokenBuffer; 455 char *Token2 = NULL; 456 char *End; 457 UINT64 Value; 458 ACPI_SIZE TokenOffset; 459 int Directive; 460 ACPI_STATUS Status; 461 462 463 if (!DirectiveToken) 464 { 465 goto SyntaxError; 466 } 467 468 Directive = PrMatchDirective (DirectiveToken); 469 if (Directive == ASL_DIRECTIVE_NOT_FOUND) 470 { 471 PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE, 472 THIS_TOKEN_OFFSET (DirectiveToken)); 473 474 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 475 "#%s: Unknown directive\n", 476 Gbl_CurrentLineNumber, DirectiveToken); 477 return; 478 } 479 480 /* 481 * Emit a line directive into the preprocessor file (.pre) after 482 * every matched directive. This is passed through to the compiler 483 * so that error/warning messages are kept in sync with the 484 * original source file. 485 */ 486 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\" // #%s\n", 487 Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename, 488 Gbl_DirectiveInfo[Directive].Name); 489 490 /* 491 * If we are currently ignoring this block and we encounter a #else or 492 * #elif, we must ignore their blocks also if the parent block is also 493 * being ignored. 494 */ 495 if (Gbl_IgnoringThisCodeBlock) 496 { 497 switch (Directive) 498 { 499 case PR_DIRECTIVE_ELSE: 500 case PR_DIRECTIVE_ELIF: 501 502 if (Gbl_DirectiveStack && 503 Gbl_DirectiveStack->IgnoringThisCodeBlock) 504 { 505 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name); 506 return; 507 } 508 break; 509 510 default: 511 break; 512 } 513 } 514 515 /* 516 * Need to always check for #else, #elif, #endif regardless of 517 * whether we are ignoring the current code block, since these 518 * are conditional code block terminators. 519 */ 520 switch (Directive) 521 { 522 case PR_DIRECTIVE_ELSE: 523 524 Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock); 525 PrDbgPrint ("Executing", "else block"); 526 return; 527 528 case PR_DIRECTIVE_ELIF: 529 530 Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock); 531 Directive = PR_DIRECTIVE_IF; 532 533 if (Gbl_IgnoringThisCodeBlock == TRUE) 534 { 535 /* Not executing the ELSE part -- all done here */ 536 PrDbgPrint ("Ignoring", "elif block"); 537 return; 538 } 539 540 /* 541 * After this, we will execute the IF part further below. 542 * First, however, pop off the original #if directive. 543 */ 544 if (ACPI_FAILURE (PrPopDirective ())) 545 { 546 PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 547 THIS_TOKEN_OFFSET (DirectiveToken)); 548 } 549 550 PrDbgPrint ("Executing", "elif block"); 551 break; 552 553 case PR_DIRECTIVE_ENDIF: 554 555 PrDbgPrint ("Executing", "endif"); 556 557 /* Pop the owning #if/#ifdef/#ifndef */ 558 559 if (ACPI_FAILURE (PrPopDirective ())) 560 { 561 PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH, 562 THIS_TOKEN_OFFSET (DirectiveToken)); 563 } 564 return; 565 566 default: 567 break; 568 } 569 570 /* Most directives have at least one argument */ 571 572 if (Gbl_DirectiveInfo[Directive].ArgCount >= 1) 573 { 574 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 575 if (!Token) 576 { 577 goto SyntaxError; 578 } 579 } 580 581 if (Gbl_DirectiveInfo[Directive].ArgCount >= 2) 582 { 583 Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 584 if (!Token2) 585 { 586 goto SyntaxError; 587 } 588 } 589 590 /* 591 * At this point, if we are ignoring the current code block, 592 * do not process any more directives (i.e., ignore them also.) 593 * For "if" style directives, open/push a new block anyway. We 594 * must do this to keep track of #endif directives 595 */ 596 if (Gbl_IgnoringThisCodeBlock) 597 { 598 switch (Directive) 599 { 600 case PR_DIRECTIVE_IF: 601 case PR_DIRECTIVE_IFDEF: 602 case PR_DIRECTIVE_IFNDEF: 603 604 PrPushDirective (Directive, Token); 605 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name); 606 break; 607 608 default: 609 break; 610 } 611 612 return; 613 } 614 615 /* 616 * Execute the directive 617 */ 618 PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name); 619 620 switch (Directive) 621 { 622 case PR_DIRECTIVE_IF: 623 624 TokenOffset = Token - Gbl_MainTokenBuffer; 625 626 /* Need to expand #define macros in the expression string first */ 627 628 Status = PrResolveIntegerExpression ( 629 &Gbl_CurrentLineBuffer[TokenOffset-1], &Value); 630 if (ACPI_FAILURE (Status)) 631 { 632 return; 633 } 634 635 PrPushDirective (Directive, Token); 636 if (!Value) 637 { 638 Gbl_IgnoringThisCodeBlock = TRUE; 639 } 640 641 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 642 "Resolved #if: %8.8X%8.8X %s\n", 643 Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value), 644 Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>"); 645 break; 646 647 case PR_DIRECTIVE_IFDEF: 648 649 PrPushDirective (Directive, Token); 650 if (!PrMatchDefine (Token)) 651 { 652 Gbl_IgnoringThisCodeBlock = TRUE; 653 } 654 655 PrDbgPrint ("Evaluated", "ifdef"); 656 break; 657 658 case PR_DIRECTIVE_IFNDEF: 659 660 PrPushDirective (Directive, Token); 661 if (PrMatchDefine (Token)) 662 { 663 Gbl_IgnoringThisCodeBlock = TRUE; 664 } 665 666 PrDbgPrint ("Evaluated", "ifndef"); 667 break; 668 669 case PR_DIRECTIVE_DEFINE: 670 /* 671 * By definition, if first char after the name is a paren, 672 * this is a function macro. 673 */ 674 TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token); 675 if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(') 676 { 677 #ifndef MACROS_SUPPORTED 678 AcpiOsPrintf ( 679 "%s ERROR - line %u: #define macros are not supported yet\n", 680 Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber); 681 exit(1); 682 #else 683 PrAddMacro (Token, Next); 684 #endif 685 } 686 else 687 { 688 /* Use the remainder of the line for the #define */ 689 690 Token2 = *Next; 691 if (Token2) 692 { 693 while ((*Token2 == ' ') || (*Token2 == '\t')) 694 { 695 Token2++; 696 } 697 698 End = Token2; 699 while (*End != '\n') 700 { 701 End++; 702 } 703 704 *End = 0; 705 } 706 else 707 { 708 Token2 = ""; 709 } 710 #if 0 711 Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next); 712 if (!Token2) 713 { 714 Token2 = ""; 715 } 716 #endif 717 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 718 "New #define: %s->%s\n", 719 Gbl_LogicalLineNumber, Token, Token2); 720 721 PrAddDefine (Token, Token2, FALSE); 722 } 723 break; 724 725 case PR_DIRECTIVE_ERROR: 726 727 /* Note: No macro expansion */ 728 729 PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE, 730 THIS_TOKEN_OFFSET (Token)); 731 732 Gbl_SourceLine = 0; 733 Gbl_NextError = Gbl_ErrorLog; 734 CmCleanupAndExit (); 735 exit(1); 736 737 case PR_DIRECTIVE_INCLUDE: 738 739 Token = PrGetNextToken (NULL, " \"<>", Next); 740 if (!Token) 741 { 742 goto SyntaxError; 743 } 744 745 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 746 "Start #include file \"%s\"\n", Gbl_CurrentLineNumber, 747 Token, Gbl_CurrentLineNumber); 748 749 PrDoIncludeFile (Token); 750 break; 751 752 case PR_DIRECTIVE_INCLUDEBUFFER: 753 754 Token = PrGetNextToken (NULL, " \"<>", Next); 755 if (!Token) 756 { 757 goto SyntaxError; 758 } 759 760 Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 761 if (!Token2) 762 { 763 goto SyntaxError; 764 } 765 766 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 767 "Start #includebuffer input from file \"%s\", buffer name %s\n", 768 Gbl_CurrentLineNumber, Token, Token2); 769 770 PrDoIncludeBuffer (Token, Token2); 771 break; 772 773 case PR_DIRECTIVE_LINE: 774 775 TokenOffset = Token - Gbl_MainTokenBuffer; 776 777 Status = PrResolveIntegerExpression ( 778 &Gbl_CurrentLineBuffer[TokenOffset-1], &Value); 779 if (ACPI_FAILURE (Status)) 780 { 781 return; 782 } 783 784 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 785 "User #line invocation %s\n", Gbl_CurrentLineNumber, 786 Token); 787 788 Gbl_CurrentLineNumber = (UINT32) Value; 789 790 /* Emit #line into the preprocessor file */ 791 792 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", 793 Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename); 794 break; 795 796 case PR_DIRECTIVE_PRAGMA: 797 798 if (!strcmp (Token, "disable")) 799 { 800 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 801 if (!Token) 802 { 803 goto SyntaxError; 804 } 805 806 TokenOffset = Token - Gbl_MainTokenBuffer; 807 AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]); 808 } 809 else if (!strcmp (Token, "message")) 810 { 811 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 812 if (!Token) 813 { 814 goto SyntaxError; 815 } 816 817 TokenOffset = Token - Gbl_MainTokenBuffer; 818 AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]); 819 } 820 else 821 { 822 PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA, 823 THIS_TOKEN_OFFSET (Token)); 824 return; 825 } 826 827 break; 828 829 case PR_DIRECTIVE_UNDEF: 830 831 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 832 "#undef: %s\n", Gbl_CurrentLineNumber, Token); 833 834 PrRemoveDefine (Token); 835 break; 836 837 case PR_DIRECTIVE_WARNING: 838 839 PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE, 840 THIS_TOKEN_OFFSET (Token)); 841 842 Gbl_SourceLine = 0; 843 Gbl_NextError = Gbl_ErrorLog; 844 break; 845 846 default: 847 848 /* Should never get here */ 849 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 850 "Unrecognized directive: %u\n", 851 Gbl_CurrentLineNumber, Directive); 852 break; 853 } 854 855 return; 856 857 SyntaxError: 858 859 PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX, 860 THIS_TOKEN_OFFSET (DirectiveToken)); 861 return; 862 } 863 864 865 /******************************************************************************* 866 * 867 * FUNCTION: PrGetNextLine, PrGetNextLineInit 868 * 869 * PARAMETERS: Handle - Open file handle for the source file 870 * 871 * RETURN: Status of the GetLine operation: 872 * AE_OK - Normal line, OK status 873 * ASL_WITHIN_COMMENT - Line is part of a multi-line comment 874 * ASL_EOF - End-of-file reached 875 * 876 * DESCRIPTION: Get the next text line from the input file. Does not strip 877 * comments. 878 * 879 ******************************************************************************/ 880 881 #define PR_NORMAL_TEXT 0 882 #define PR_MULTI_LINE_COMMENT 1 883 #define PR_SINGLE_LINE_COMMENT 2 884 #define PR_QUOTED_STRING 3 885 886 static UINT8 AcpiGbl_LineScanState = PR_NORMAL_TEXT; 887 888 static void 889 PrGetNextLineInit ( 890 void) 891 { 892 AcpiGbl_LineScanState = 0; 893 } 894 895 static UINT32 896 PrGetNextLine ( 897 FILE *Handle) 898 { 899 UINT32 i; 900 int c = 0; 901 int PreviousChar; 902 903 904 /* Always clear the global line buffer */ 905 906 memset (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize); 907 for (i = 0; ;) 908 { 909 /* 910 * If line is too long, expand the line buffers. Also increases 911 * Gbl_LineBufferSize. 912 */ 913 if (i >= Gbl_LineBufferSize) 914 { 915 UtExpandLineBuffers (); 916 } 917 918 PreviousChar = c; 919 c = getc (Handle); 920 if (c == EOF) 921 { 922 return (ASL_EOF); 923 } 924 925 /* Update state machine as necessary */ 926 927 switch (AcpiGbl_LineScanState) 928 { 929 case PR_NORMAL_TEXT: 930 931 /* Check for multi-line comment start */ 932 933 if ((PreviousChar == '/') && (c == '*')) 934 { 935 AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT; 936 } 937 938 /* Check for single-line comment start */ 939 940 else if ((PreviousChar == '/') && (c == '/')) 941 { 942 AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT; 943 } 944 945 /* Check for quoted string start */ 946 947 else if (PreviousChar == '"') 948 { 949 AcpiGbl_LineScanState = PR_QUOTED_STRING; 950 } 951 break; 952 953 case PR_QUOTED_STRING: 954 955 if (PreviousChar == '"') 956 { 957 AcpiGbl_LineScanState = PR_NORMAL_TEXT; 958 } 959 break; 960 961 case PR_MULTI_LINE_COMMENT: 962 963 /* Check for multi-line comment end */ 964 965 if ((PreviousChar == '*') && (c == '/')) 966 { 967 AcpiGbl_LineScanState = PR_NORMAL_TEXT; 968 } 969 break; 970 971 case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */ 972 default: 973 break; 974 } 975 976 /* Always copy the character into line buffer */ 977 978 Gbl_CurrentLineBuffer[i] = (char) c; 979 i++; 980 981 /* Always exit on end-of-line */ 982 983 if (c == '\n') 984 { 985 /* Handle multi-line comments */ 986 987 if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT) 988 { 989 return (ASL_WITHIN_COMMENT); 990 } 991 992 /* End of single-line comment */ 993 994 if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT) 995 { 996 AcpiGbl_LineScanState = PR_NORMAL_TEXT; 997 return (AE_OK); 998 } 999 1000 /* Blank line */ 1001 1002 if (i == 1) 1003 { 1004 return (ASL_BLANK_LINE); 1005 } 1006 1007 return (AE_OK); 1008 } 1009 } 1010 } 1011 1012 1013 /******************************************************************************* 1014 * 1015 * FUNCTION: PrMatchDirective 1016 * 1017 * PARAMETERS: Directive - Pointer to directive name token 1018 * 1019 * RETURN: Index into command array, -1 if not found 1020 * 1021 * DESCRIPTION: Lookup the incoming directive in the known directives table. 1022 * 1023 ******************************************************************************/ 1024 1025 static int 1026 PrMatchDirective ( 1027 char *Directive) 1028 { 1029 int i; 1030 1031 1032 if (!Directive || Directive[0] == 0) 1033 { 1034 return (ASL_DIRECTIVE_NOT_FOUND); 1035 } 1036 1037 for (i = 0; Gbl_DirectiveInfo[i].Name; i++) 1038 { 1039 if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive)) 1040 { 1041 return (i); 1042 } 1043 } 1044 1045 return (ASL_DIRECTIVE_NOT_FOUND); /* Command not recognized */ 1046 } 1047 1048 1049 /******************************************************************************* 1050 * 1051 * FUNCTION: PrPushDirective 1052 * 1053 * PARAMETERS: Directive - Encoded directive ID 1054 * Argument - String containing argument to the 1055 * directive 1056 * 1057 * RETURN: None 1058 * 1059 * DESCRIPTION: Push an item onto the directive stack. Used for processing 1060 * nested #if/#else type conditional compilation directives. 1061 * Specifically: Used on detection of #if/#ifdef/#ifndef to open 1062 * a block. 1063 * 1064 ******************************************************************************/ 1065 1066 static void 1067 PrPushDirective ( 1068 int Directive, 1069 char *Argument) 1070 { 1071 DIRECTIVE_INFO *Info; 1072 1073 1074 /* Allocate and populate a stack info item */ 1075 1076 Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO)); 1077 1078 Info->Next = Gbl_DirectiveStack; 1079 Info->Directive = Directive; 1080 Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock; 1081 strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH); 1082 1083 DbgPrint (ASL_DEBUG_OUTPUT, 1084 "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n", 1085 Gbl_CurrentLineNumber, Gbl_IfDepth, 1086 Gbl_IgnoringThisCodeBlock ? "I" : "E", 1087 Gbl_IfDepth * 4, " ", 1088 Gbl_DirectiveInfo[Directive].Name, 1089 Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE"); 1090 1091 /* Push new item */ 1092 1093 Gbl_DirectiveStack = Info; 1094 Gbl_IfDepth++; 1095 } 1096 1097 1098 /******************************************************************************* 1099 * 1100 * FUNCTION: PrPopDirective 1101 * 1102 * PARAMETERS: None 1103 * 1104 * RETURN: Status. Error if the stack is empty. 1105 * 1106 * DESCRIPTION: Pop an item off the directive stack. Used for processing 1107 * nested #if/#else type conditional compilation directives. 1108 * Specifically: Used on detection of #elif and #endif to remove 1109 * the original #if/#ifdef/#ifndef from the stack and close 1110 * the block. 1111 * 1112 ******************************************************************************/ 1113 1114 static ACPI_STATUS 1115 PrPopDirective ( 1116 void) 1117 { 1118 DIRECTIVE_INFO *Info; 1119 1120 1121 /* Check for empty stack */ 1122 1123 Info = Gbl_DirectiveStack; 1124 if (!Info) 1125 { 1126 return (AE_ERROR); 1127 } 1128 1129 /* Pop one item, keep globals up-to-date */ 1130 1131 Gbl_IfDepth--; 1132 Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock; 1133 Gbl_DirectiveStack = Info->Next; 1134 1135 DbgPrint (ASL_DEBUG_OUTPUT, 1136 "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n", 1137 Gbl_CurrentLineNumber, Gbl_IfDepth, 1138 Gbl_IgnoringThisCodeBlock ? "I" : "E", 1139 Gbl_IfDepth * 4, " ", 1140 Gbl_DirectiveInfo[Info->Directive].Name, 1141 Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE"); 1142 1143 ACPI_FREE (Info); 1144 return (AE_OK); 1145 } 1146 1147 1148 /******************************************************************************* 1149 * 1150 * FUNCTION: PrDbgPrint 1151 * 1152 * PARAMETERS: Action - Action being performed 1153 * DirectiveName - Directive being processed 1154 * 1155 * RETURN: None 1156 * 1157 * DESCRIPTION: Special debug print for directive processing. 1158 * 1159 ******************************************************************************/ 1160 1161 static void 1162 PrDbgPrint ( 1163 char *Action, 1164 char *DirectiveName) 1165 { 1166 1167 DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] " 1168 "%*s %s #%s, IfDepth %u\n", 1169 Gbl_CurrentLineNumber, Gbl_IfDepth, 1170 Gbl_IgnoringThisCodeBlock ? "I" : "E", 1171 Gbl_IfDepth * 4, " ", 1172 Action, DirectiveName, Gbl_IfDepth); 1173 } 1174 1175 1176 /******************************************************************************* 1177 * 1178 * FUNCTION: PrDoIncludeFile 1179 * 1180 * PARAMETERS: Pathname - Name of the input file 1181 * 1182 * RETURN: None. 1183 * 1184 * DESCRIPTION: Open an include file, from #include. 1185 * 1186 ******************************************************************************/ 1187 1188 static void 1189 PrDoIncludeFile ( 1190 char *Pathname) 1191 { 1192 char *FullPathname; 1193 1194 1195 (void) PrOpenIncludeFile (Pathname, "r", &FullPathname); 1196 } 1197 1198 1199 /******************************************************************************* 1200 * 1201 * FUNCTION: PrDoIncludeBuffer 1202 * 1203 * PARAMETERS: Pathname - Name of the input binary file 1204 * BufferName - ACPI namepath of the buffer 1205 * 1206 * RETURN: None. 1207 * 1208 * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents 1209 * of the file are emitted into the buffer object as ascii 1210 * hex data. From #includebuffer. 1211 * 1212 ******************************************************************************/ 1213 1214 static void 1215 PrDoIncludeBuffer ( 1216 char *Pathname, 1217 char *BufferName) 1218 { 1219 char *FullPathname; 1220 FILE *BinaryBufferFile; 1221 UINT32 i = 0; 1222 UINT8 c; 1223 1224 1225 BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname); 1226 if (!BinaryBufferFile) 1227 { 1228 return; 1229 } 1230 1231 /* Emit "Name (XXXX, Buffer() {" header */ 1232 1233 FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName); 1234 1235 /* Dump the entire file in ascii hex format */ 1236 1237 while (fread (&c, 1, 1, BinaryBufferFile)) 1238 { 1239 if (!(i % 8)) 1240 { 1241 FlPrintFile (ASL_FILE_PREPROCESSOR, "\n ", c); 1242 } 1243 1244 FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c); 1245 i++; 1246 } 1247 1248 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 1249 "#includebuffer: read %u bytes from %s\n", 1250 Gbl_CurrentLineNumber, i, FullPathname); 1251 1252 /* Close the Name() operator */ 1253 1254 FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName); 1255 fclose (BinaryBufferFile); 1256 } 1257