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