1 /****************************************************************************** 2 * 3 * Module Name: prscan - Preprocessor start-up and file scan module 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, 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 <contrib/dev/acpica/compiler/aslcompiler.h> 47 #include <contrib/dev/acpica/compiler/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_IGNORE_LINE) 338 { 339 goto WriteEntireLine; 340 } 341 342 /* Need a copy of the input line for strok() */ 343 344 strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer); 345 Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next); 346 OffsetAdjust = 0; 347 348 /* All preprocessor directives must begin with '#' */ 349 350 if (Token && (*Token == '#')) 351 { 352 if (strlen (Token) == 1) 353 { 354 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next); 355 } 356 else 357 { 358 Token++; /* Skip leading # */ 359 } 360 361 /* Execute the directive, do not write line to output file */ 362 363 PrDoDirective (Token, &Next); 364 continue; 365 } 366 367 /* 368 * If we are currently within the part of an IF/ELSE block that is 369 * FALSE, ignore the line and do not write it to the output file. 370 * This continues until an #else or #endif is encountered. 371 */ 372 if (Gbl_IgnoringThisCodeBlock) 373 { 374 continue; 375 } 376 377 /* Match and replace all #defined names within this source line */ 378 379 while (Token) 380 { 381 DefineInfo = PrMatchDefine (Token); 382 if (DefineInfo) 383 { 384 if (DefineInfo->Body) 385 { 386 /* This is a macro */ 387 388 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 389 "Matched Macro: %s->%s\n", 390 Gbl_CurrentLineNumber, DefineInfo->Identifier, 391 DefineInfo->Replacement); 392 393 PrDoMacroInvocation (Gbl_MainTokenBuffer, Token, 394 DefineInfo, &Next); 395 } 396 else 397 { 398 ReplaceString = DefineInfo->Replacement; 399 400 /* Replace the name in the original line buffer */ 401 402 TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust; 403 PrReplaceData ( 404 &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token), 405 ReplaceString, strlen (ReplaceString)); 406 407 /* Adjust for length difference between old and new name length */ 408 409 OffsetAdjust += strlen (ReplaceString) - strlen (Token); 410 411 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 412 "Matched #define: %s->%s\n", 413 Gbl_CurrentLineNumber, Token, 414 *ReplaceString ? ReplaceString : "(NULL STRING)"); 415 } 416 } 417 418 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next); 419 } 420 421 Gbl_PreprocessorLineNumber++; 422 423 424 WriteEntireLine: 425 /* 426 * Now we can write the possibly modified source line to the 427 * preprocessor file(s). 428 */ 429 FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer, 430 strlen (Gbl_CurrentLineBuffer)); 431 } 432 } 433 434 435 /******************************************************************************* 436 * 437 * FUNCTION: PrDoDirective 438 * 439 * PARAMETERS: Directive - Pointer to directive name token 440 * Next - "Next" buffer from GetNextToken 441 * 442 * RETURN: None. 443 * 444 * DESCRIPTION: Main processing for all preprocessor directives 445 * 446 ******************************************************************************/ 447 448 static void 449 PrDoDirective ( 450 char *DirectiveToken, 451 char **Next) 452 { 453 char *Token = Gbl_MainTokenBuffer; 454 char *Token2 = NULL; 455 char *End; 456 UINT64 Value; 457 ACPI_SIZE TokenOffset; 458 int Directive; 459 ACPI_STATUS Status; 460 461 462 if (!DirectiveToken) 463 { 464 goto SyntaxError; 465 } 466 467 Directive = PrMatchDirective (DirectiveToken); 468 if (Directive == ASL_DIRECTIVE_NOT_FOUND) 469 { 470 PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE, 471 THIS_TOKEN_OFFSET (DirectiveToken)); 472 473 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 474 "#%s: Unknown directive\n", 475 Gbl_CurrentLineNumber, DirectiveToken); 476 return; 477 } 478 479 /* 480 * Emit a line directive into the preprocessor file (.pre) after 481 * every matched directive. This is passed through to the compiler 482 * so that error/warning messages are kept in sync with the 483 * original source file. 484 */ 485 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\" // #%s\n", 486 Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename, 487 Gbl_DirectiveInfo[Directive].Name); 488 489 /* 490 * If we are currently ignoring this block and we encounter a #else or 491 * #elif, we must ignore their blocks also if the parent block is also 492 * being ignored. 493 */ 494 if (Gbl_IgnoringThisCodeBlock) 495 { 496 switch (Directive) 497 { 498 case PR_DIRECTIVE_ELSE: 499 case PR_DIRECTIVE_ELIF: 500 501 if (Gbl_DirectiveStack && 502 Gbl_DirectiveStack->IgnoringThisCodeBlock) 503 { 504 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name); 505 return; 506 } 507 break; 508 509 default: 510 break; 511 } 512 } 513 514 /* 515 * Need to always check for #else, #elif, #endif regardless of 516 * whether we are ignoring the current code block, since these 517 * are conditional code block terminators. 518 */ 519 switch (Directive) 520 { 521 case PR_DIRECTIVE_ELSE: 522 523 Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock); 524 PrDbgPrint ("Executing", "else block"); 525 return; 526 527 case PR_DIRECTIVE_ELIF: 528 529 Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock); 530 Directive = PR_DIRECTIVE_IF; 531 532 if (Gbl_IgnoringThisCodeBlock == TRUE) 533 { 534 /* Not executing the ELSE part -- all done here */ 535 PrDbgPrint ("Ignoring", "elif block"); 536 return; 537 } 538 539 /* 540 * After this, we will execute the IF part further below. 541 * First, however, pop off the original #if directive. 542 */ 543 if (ACPI_FAILURE (PrPopDirective ())) 544 { 545 PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 546 THIS_TOKEN_OFFSET (DirectiveToken)); 547 } 548 549 PrDbgPrint ("Executing", "elif block"); 550 break; 551 552 case PR_DIRECTIVE_ENDIF: 553 554 PrDbgPrint ("Executing", "endif"); 555 556 /* Pop the owning #if/#ifdef/#ifndef */ 557 558 if (ACPI_FAILURE (PrPopDirective ())) 559 { 560 PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH, 561 THIS_TOKEN_OFFSET (DirectiveToken)); 562 } 563 return; 564 565 default: 566 break; 567 } 568 569 /* Most directives have at least one argument */ 570 571 if (Gbl_DirectiveInfo[Directive].ArgCount >= 1) 572 { 573 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 574 if (!Token) 575 { 576 goto SyntaxError; 577 } 578 } 579 580 if (Gbl_DirectiveInfo[Directive].ArgCount >= 2) 581 { 582 Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 583 if (!Token2) 584 { 585 goto SyntaxError; 586 } 587 } 588 589 /* 590 * At this point, if we are ignoring the current code block, 591 * do not process any more directives (i.e., ignore them also.) 592 * For "if" style directives, open/push a new block anyway. We 593 * must do this to keep track of #endif directives 594 */ 595 if (Gbl_IgnoringThisCodeBlock) 596 { 597 switch (Directive) 598 { 599 case PR_DIRECTIVE_IF: 600 case PR_DIRECTIVE_IFDEF: 601 case PR_DIRECTIVE_IFNDEF: 602 603 PrPushDirective (Directive, Token); 604 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name); 605 break; 606 607 default: 608 break; 609 } 610 611 return; 612 } 613 614 /* 615 * Execute the directive 616 */ 617 PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name); 618 619 switch (Directive) 620 { 621 case PR_DIRECTIVE_IF: 622 623 TokenOffset = Token - Gbl_MainTokenBuffer; 624 625 /* Need to expand #define macros in the expression string first */ 626 627 Status = PrResolveIntegerExpression ( 628 &Gbl_CurrentLineBuffer[TokenOffset-1], &Value); 629 if (ACPI_FAILURE (Status)) 630 { 631 return; 632 } 633 634 PrPushDirective (Directive, Token); 635 if (!Value) 636 { 637 Gbl_IgnoringThisCodeBlock = TRUE; 638 } 639 640 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 641 "Resolved #if: %8.8X%8.8X %s\n", 642 Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value), 643 Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>"); 644 break; 645 646 case PR_DIRECTIVE_IFDEF: 647 648 PrPushDirective (Directive, Token); 649 if (!PrMatchDefine (Token)) 650 { 651 Gbl_IgnoringThisCodeBlock = TRUE; 652 } 653 654 PrDbgPrint ("Evaluated", "ifdef"); 655 break; 656 657 case PR_DIRECTIVE_IFNDEF: 658 659 PrPushDirective (Directive, Token); 660 if (PrMatchDefine (Token)) 661 { 662 Gbl_IgnoringThisCodeBlock = TRUE; 663 } 664 665 PrDbgPrint ("Evaluated", "ifndef"); 666 break; 667 668 case PR_DIRECTIVE_DEFINE: 669 /* 670 * By definition, if first char after the name is a paren, 671 * this is a function macro. 672 */ 673 TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token); 674 if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(') 675 { 676 #ifndef MACROS_SUPPORTED 677 AcpiOsPrintf ( 678 "%s ERROR - line %u: #define macros are not supported yet\n", 679 Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber); 680 exit(1); 681 #else 682 PrAddMacro (Token, Next); 683 #endif 684 } 685 else 686 { 687 /* Use the remainder of the line for the #define */ 688 689 Token2 = *Next; 690 if (Token2) 691 { 692 while ((*Token2 == ' ') || (*Token2 == '\t')) 693 { 694 Token2++; 695 } 696 697 End = Token2; 698 while (*End != '\n') 699 { 700 End++; 701 } 702 703 *End = 0; 704 } 705 else 706 { 707 Token2 = ""; 708 } 709 #if 0 710 Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next); 711 if (!Token2) 712 { 713 Token2 = ""; 714 } 715 #endif 716 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 717 "New #define: %s->%s\n", 718 Gbl_LogicalLineNumber, Token, Token2); 719 720 PrAddDefine (Token, Token2, FALSE); 721 } 722 break; 723 724 case PR_DIRECTIVE_ERROR: 725 726 /* Note: No macro expansion */ 727 728 PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE, 729 THIS_TOKEN_OFFSET (Token)); 730 731 Gbl_SourceLine = 0; 732 Gbl_NextError = Gbl_ErrorLog; 733 CmCleanupAndExit (); 734 exit(1); 735 736 case PR_DIRECTIVE_INCLUDE: 737 738 Token = PrGetNextToken (NULL, " \"<>", Next); 739 if (!Token) 740 { 741 goto SyntaxError; 742 } 743 744 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 745 "Start #include file \"%s\"\n", Gbl_CurrentLineNumber, 746 Token, Gbl_CurrentLineNumber); 747 748 PrDoIncludeFile (Token); 749 break; 750 751 case PR_DIRECTIVE_INCLUDEBUFFER: 752 753 Token = PrGetNextToken (NULL, " \"<>", Next); 754 if (!Token) 755 { 756 goto SyntaxError; 757 } 758 759 Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 760 if (!Token2) 761 { 762 goto SyntaxError; 763 } 764 765 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 766 "Start #includebuffer input from file \"%s\", buffer name %s\n", 767 Gbl_CurrentLineNumber, Token, Token2); 768 769 PrDoIncludeBuffer (Token, Token2); 770 break; 771 772 case PR_DIRECTIVE_LINE: 773 774 TokenOffset = Token - Gbl_MainTokenBuffer; 775 776 Status = PrResolveIntegerExpression ( 777 &Gbl_CurrentLineBuffer[TokenOffset-1], &Value); 778 if (ACPI_FAILURE (Status)) 779 { 780 return; 781 } 782 783 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 784 "User #line invocation %s\n", Gbl_CurrentLineNumber, 785 Token); 786 787 Gbl_CurrentLineNumber = (UINT32) Value; 788 789 /* Emit #line into the preprocessor file */ 790 791 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", 792 Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename); 793 break; 794 795 case PR_DIRECTIVE_PRAGMA: 796 797 if (!strcmp (Token, "disable")) 798 { 799 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 800 if (!Token) 801 { 802 goto SyntaxError; 803 } 804 805 TokenOffset = Token - Gbl_MainTokenBuffer; 806 AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]); 807 } 808 else if (!strcmp (Token, "message")) 809 { 810 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); 811 if (!Token) 812 { 813 goto SyntaxError; 814 } 815 816 TokenOffset = Token - Gbl_MainTokenBuffer; 817 AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]); 818 } 819 else 820 { 821 PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA, 822 THIS_TOKEN_OFFSET (Token)); 823 return; 824 } 825 826 break; 827 828 case PR_DIRECTIVE_UNDEF: 829 830 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 831 "#undef: %s\n", Gbl_CurrentLineNumber, Token); 832 833 PrRemoveDefine (Token); 834 break; 835 836 case PR_DIRECTIVE_WARNING: 837 838 PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE, 839 THIS_TOKEN_OFFSET (Token)); 840 841 Gbl_SourceLine = 0; 842 Gbl_NextError = Gbl_ErrorLog; 843 break; 844 845 default: 846 847 /* Should never get here */ 848 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 849 "Unrecognized directive: %u\n", 850 Gbl_CurrentLineNumber, Directive); 851 break; 852 } 853 854 return; 855 856 SyntaxError: 857 858 PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX, 859 THIS_TOKEN_OFFSET (DirectiveToken)); 860 return; 861 } 862 863 864 /******************************************************************************* 865 * 866 * FUNCTION: PrGetNextLine, PrGetNextLineInit 867 * 868 * PARAMETERS: Handle - Open file handle for the source file 869 * 870 * RETURN: Status of the GetLine operation: 871 * AE_OK - Normal line, OK status 872 * ASL_IGNORE_LINE - Line is blank or part of a multi-line 873 * 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 /* 923 * On EOF: If there is anything in the line buffer, terminate 924 * it with a newline, and catch the EOF on the next call 925 * to this function. 926 */ 927 if (i > 0) 928 { 929 Gbl_CurrentLineBuffer[i] = '\n'; 930 return (AE_OK); 931 } 932 933 return (ASL_EOF); 934 } 935 936 /* Update state machine as necessary */ 937 938 switch (AcpiGbl_LineScanState) 939 { 940 case PR_NORMAL_TEXT: 941 942 /* Check for multi-line comment start */ 943 944 if ((PreviousChar == '/') && (c == '*')) 945 { 946 AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT; 947 } 948 949 /* Check for single-line comment start */ 950 951 else if ((PreviousChar == '/') && (c == '/')) 952 { 953 AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT; 954 } 955 956 /* Check for quoted string start */ 957 958 else if (PreviousChar == '"') 959 { 960 AcpiGbl_LineScanState = PR_QUOTED_STRING; 961 } 962 break; 963 964 case PR_QUOTED_STRING: 965 966 if (PreviousChar == '"') 967 { 968 AcpiGbl_LineScanState = PR_NORMAL_TEXT; 969 } 970 break; 971 972 case PR_MULTI_LINE_COMMENT: 973 974 /* Check for multi-line comment end */ 975 976 if ((PreviousChar == '*') && (c == '/')) 977 { 978 AcpiGbl_LineScanState = PR_NORMAL_TEXT; 979 } 980 break; 981 982 case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */ 983 default: 984 break; 985 } 986 987 /* Always copy the character into line buffer */ 988 989 Gbl_CurrentLineBuffer[i] = (char) c; 990 i++; 991 992 /* Always exit on end-of-line */ 993 994 if (c == '\n') 995 { 996 /* Handle multi-line comments */ 997 998 if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT) 999 { 1000 return (ASL_IGNORE_LINE); 1001 } 1002 1003 /* End of single-line comment */ 1004 1005 if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT) 1006 { 1007 AcpiGbl_LineScanState = PR_NORMAL_TEXT; 1008 return (AE_OK); 1009 } 1010 1011 /* Blank line */ 1012 1013 if (i == 1) 1014 { 1015 return (ASL_IGNORE_LINE); 1016 } 1017 1018 return (AE_OK); 1019 } 1020 } 1021 } 1022 1023 1024 /******************************************************************************* 1025 * 1026 * FUNCTION: PrMatchDirective 1027 * 1028 * PARAMETERS: Directive - Pointer to directive name token 1029 * 1030 * RETURN: Index into command array, -1 if not found 1031 * 1032 * DESCRIPTION: Lookup the incoming directive in the known directives table. 1033 * 1034 ******************************************************************************/ 1035 1036 static int 1037 PrMatchDirective ( 1038 char *Directive) 1039 { 1040 int i; 1041 1042 1043 if (!Directive || Directive[0] == 0) 1044 { 1045 return (ASL_DIRECTIVE_NOT_FOUND); 1046 } 1047 1048 for (i = 0; Gbl_DirectiveInfo[i].Name; i++) 1049 { 1050 if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive)) 1051 { 1052 return (i); 1053 } 1054 } 1055 1056 return (ASL_DIRECTIVE_NOT_FOUND); /* Command not recognized */ 1057 } 1058 1059 1060 /******************************************************************************* 1061 * 1062 * FUNCTION: PrPushDirective 1063 * 1064 * PARAMETERS: Directive - Encoded directive ID 1065 * Argument - String containing argument to the 1066 * directive 1067 * 1068 * RETURN: None 1069 * 1070 * DESCRIPTION: Push an item onto the directive stack. Used for processing 1071 * nested #if/#else type conditional compilation directives. 1072 * Specifically: Used on detection of #if/#ifdef/#ifndef to open 1073 * a block. 1074 * 1075 ******************************************************************************/ 1076 1077 static void 1078 PrPushDirective ( 1079 int Directive, 1080 char *Argument) 1081 { 1082 DIRECTIVE_INFO *Info; 1083 1084 1085 /* Allocate and populate a stack info item */ 1086 1087 Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO)); 1088 1089 Info->Next = Gbl_DirectiveStack; 1090 Info->Directive = Directive; 1091 Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock; 1092 strncpy (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 Gbl_CurrentLineNumber, Gbl_IfDepth, 1097 Gbl_IgnoringThisCodeBlock ? "I" : "E", 1098 Gbl_IfDepth * 4, " ", 1099 Gbl_DirectiveInfo[Directive].Name, 1100 Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE"); 1101 1102 /* Push new item */ 1103 1104 Gbl_DirectiveStack = Info; 1105 Gbl_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 = Gbl_DirectiveStack; 1135 if (!Info) 1136 { 1137 return (AE_ERROR); 1138 } 1139 1140 /* Pop one item, keep globals up-to-date */ 1141 1142 Gbl_IfDepth--; 1143 Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock; 1144 Gbl_DirectiveStack = Info->Next; 1145 1146 DbgPrint (ASL_DEBUG_OUTPUT, 1147 "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n", 1148 Gbl_CurrentLineNumber, Gbl_IfDepth, 1149 Gbl_IgnoringThisCodeBlock ? "I" : "E", 1150 Gbl_IfDepth * 4, " ", 1151 Gbl_DirectiveInfo[Info->Directive].Name, 1152 Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE"); 1153 1154 ACPI_FREE (Info); 1155 return (AE_OK); 1156 } 1157 1158 1159 /******************************************************************************* 1160 * 1161 * FUNCTION: PrDbgPrint 1162 * 1163 * PARAMETERS: Action - Action being performed 1164 * DirectiveName - Directive being processed 1165 * 1166 * RETURN: None 1167 * 1168 * DESCRIPTION: Special debug print for directive processing. 1169 * 1170 ******************************************************************************/ 1171 1172 static void 1173 PrDbgPrint ( 1174 char *Action, 1175 char *DirectiveName) 1176 { 1177 1178 DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] " 1179 "%*s %s #%s, IfDepth %u\n", 1180 Gbl_CurrentLineNumber, Gbl_IfDepth, 1181 Gbl_IgnoringThisCodeBlock ? "I" : "E", 1182 Gbl_IfDepth * 4, " ", 1183 Action, DirectiveName, Gbl_IfDepth); 1184 } 1185 1186 1187 /******************************************************************************* 1188 * 1189 * FUNCTION: PrDoIncludeFile 1190 * 1191 * PARAMETERS: Pathname - Name of the input file 1192 * 1193 * RETURN: None. 1194 * 1195 * DESCRIPTION: Open an include file, from #include. 1196 * 1197 ******************************************************************************/ 1198 1199 static void 1200 PrDoIncludeFile ( 1201 char *Pathname) 1202 { 1203 char *FullPathname; 1204 1205 1206 (void) PrOpenIncludeFile (Pathname, "r", &FullPathname); 1207 } 1208 1209 1210 /******************************************************************************* 1211 * 1212 * FUNCTION: PrDoIncludeBuffer 1213 * 1214 * PARAMETERS: Pathname - Name of the input binary file 1215 * BufferName - ACPI namepath of the buffer 1216 * 1217 * RETURN: None. 1218 * 1219 * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents 1220 * of the file are emitted into the buffer object as ascii 1221 * hex data. From #includebuffer. 1222 * 1223 ******************************************************************************/ 1224 1225 static void 1226 PrDoIncludeBuffer ( 1227 char *Pathname, 1228 char *BufferName) 1229 { 1230 char *FullPathname; 1231 FILE *BinaryBufferFile; 1232 UINT32 i = 0; 1233 UINT8 c; 1234 1235 1236 BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname); 1237 if (!BinaryBufferFile) 1238 { 1239 return; 1240 } 1241 1242 /* Emit "Name (XXXX, Buffer() {" header */ 1243 1244 FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName); 1245 1246 /* Dump the entire file in ascii hex format */ 1247 1248 while (fread (&c, 1, 1, BinaryBufferFile)) 1249 { 1250 if (!(i % 8)) 1251 { 1252 FlPrintFile (ASL_FILE_PREPROCESSOR, "\n ", c); 1253 } 1254 1255 FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c); 1256 i++; 1257 } 1258 1259 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 1260 "#includebuffer: read %u bytes from %s\n", 1261 Gbl_CurrentLineNumber, i, FullPathname); 1262 1263 /* Close the Name() operator */ 1264 1265 FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName); 1266 fclose (BinaryBufferFile); 1267 } 1268