1 /******************************************************************************
   2  *
   3  * Module Name: prscan - Preprocessor start-up and file scan module
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, 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 int
  71 PrMatchDirective (
  72     char                    *Directive);
  73 
  74 static void
  75 PrPushDirective (
  76     int                     Directive,
  77     char                    *Argument);
  78 
  79 static ACPI_STATUS
  80 PrPopDirective (
  81     void);
  82 
  83 static void
  84 PrDbgPrint (
  85     char                    *Action,
  86     char                    *DirectiveName);
  87 
  88 
  89 /*
  90  * Supported preprocessor directives
  91  */
  92 static const PR_DIRECTIVE_INFO      Gbl_DirectiveInfo[] =
  93 {
  94     {"define",  1},
  95     {"elif",    0}, /* Converted to #else..#if internally */
  96     {"else",    0},
  97     {"endif",   0},
  98     {"error",   1},
  99     {"if",      1},
 100     {"ifdef",   1},
 101     {"ifndef",  1},
 102     {"include", 0}, /* Argument is not standard format, so 0 */
 103     {"line",    1},
 104     {"pragma",  1},
 105     {"undef",   1},
 106     {"warning", 1},
 107     {NULL,      0}
 108 };
 109 
 110 enum Gbl_DirectiveIndexes
 111 {
 112     PR_DIRECTIVE_DEFINE = 0,
 113     PR_DIRECTIVE_ELIF,
 114     PR_DIRECTIVE_ELSE,
 115     PR_DIRECTIVE_ENDIF,
 116     PR_DIRECTIVE_ERROR,
 117     PR_DIRECTIVE_IF,
 118     PR_DIRECTIVE_IFDEF,
 119     PR_DIRECTIVE_IFNDEF,
 120     PR_DIRECTIVE_INCLUDE,
 121     PR_DIRECTIVE_LINE,
 122     PR_DIRECTIVE_PRAGMA,
 123     PR_DIRECTIVE_UNDEF,
 124     PR_DIRECTIVE_WARNING,
 125 };
 126 
 127 #define ASL_DIRECTIVE_NOT_FOUND     -1
 128 
 129 
 130 /*******************************************************************************
 131  *
 132  * FUNCTION:    PrInitializePreprocessor
 133  *
 134  * PARAMETERS:  None
 135  *
 136  * RETURN:      None
 137  *
 138  * DESCRIPTION: Startup initialization for the Preprocessor.
 139  *
 140  ******************************************************************************/
 141 
 142 void
 143 PrInitializePreprocessor (
 144     void)
 145 {
 146     /* Init globals and the list of #defines */
 147 
 148     PrInitializeGlobals ();
 149     Gbl_DefineList = NULL;
 150 }
 151 
 152 
 153 /*******************************************************************************
 154  *
 155  * FUNCTION:    PrInitializeGlobals
 156  *
 157  * PARAMETERS:  None
 158  *
 159  * RETURN:      None
 160  *
 161  * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup
 162  *              initialization and re-initialization between compiles during
 163  *              a multiple source file compile.
 164  *
 165  ******************************************************************************/
 166 
 167 void
 168 PrInitializeGlobals (
 169     void)
 170 {
 171     /* Init globals */
 172 
 173     Gbl_InputFileList = NULL;
 174     Gbl_CurrentLineNumber = 0;
 175     Gbl_PreprocessorLineNumber = 1;
 176     Gbl_PreprocessorError = FALSE;
 177 
 178     /* These are used to track #if/#else blocks (possibly nested) */
 179 
 180     Gbl_IfDepth = 0;
 181     Gbl_IgnoringThisCodeBlock = FALSE;
 182     Gbl_DirectiveStack = NULL;
 183 }
 184 
 185 
 186 /*******************************************************************************
 187  *
 188  * FUNCTION:    PrTerminatePreprocessor
 189  *
 190  * PARAMETERS:  None
 191  *
 192  * RETURN:      None
 193  *
 194  * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any
 195  *              defines that were specified on the command line, in order to
 196  *              support multiple compiles with a single compiler invocation.
 197  *
 198  ******************************************************************************/
 199 
 200 void
 201 PrTerminatePreprocessor (
 202     void)
 203 {
 204     PR_DEFINE_INFO          *DefineInfo;
 205 
 206 
 207     /*
 208      * The persistent defines (created on the command line) are always at the
 209      * end of the list. We save them.
 210      */
 211     while ((Gbl_DefineList) && (!Gbl_DefineList->Persist))
 212     {
 213         DefineInfo = Gbl_DefineList;
 214         Gbl_DefineList = DefineInfo->Next;
 215 
 216         ACPI_FREE (DefineInfo->Replacement);
 217         ACPI_FREE (DefineInfo->Identifier);
 218         ACPI_FREE (DefineInfo);
 219     }
 220 }
 221 
 222 
 223 /*******************************************************************************
 224  *
 225  * FUNCTION:    PrDoPreprocess
 226  *
 227  * PARAMETERS:  None
 228  *
 229  * RETURN:      None
 230  *
 231  * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must
 232  *              be already open. Handles multiple input files via the
 233  *              #include directive.
 234  *
 235  ******************************************************************************/
 236 
 237 void
 238 PrDoPreprocess (
 239     void)
 240 {
 241     BOOLEAN                 MoreInputFiles;
 242 
 243 
 244     DbgPrint (ASL_DEBUG_OUTPUT, "Starting preprocessing phase\n\n");
 245 
 246 
 247     FlSeekFile (ASL_FILE_INPUT, 0);
 248     PrDumpPredefinedNames ();
 249 
 250     /* Main preprocessor loop, handles include files */
 251 
 252     do
 253     {
 254         PrPreprocessInputFile ();
 255         MoreInputFiles = PrPopInputFileStack ();
 256 
 257     } while (MoreInputFiles);
 258 
 259     /* Point compiler input to the new preprocessor output file (.i) */
 260 
 261     FlCloseFile (ASL_FILE_INPUT);
 262     Gbl_Files[ASL_FILE_INPUT].Handle = Gbl_Files[ASL_FILE_PREPROCESSOR].Handle;
 263     AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle;
 264 
 265     /* Reset globals to allow compiler to run */
 266 
 267     FlSeekFile (ASL_FILE_INPUT, 0);
 268     Gbl_CurrentLineNumber = 1;
 269 
 270     DbgPrint (ASL_DEBUG_OUTPUT, "Preprocessing phase complete \n\n");
 271 }
 272 
 273 
 274 /*******************************************************************************
 275  *
 276  * FUNCTION:    PrPreprocessInputFile
 277  *
 278  * PARAMETERS:  None
 279  *
 280  * RETURN:      None
 281  *
 282  * DESCRIPTION: Preprocess one entire file, line-by-line.
 283  *
 284  * Input:  Raw user ASL from ASL_FILE_INPUT
 285  * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR
 286  *
 287  ******************************************************************************/
 288 
 289 static void
 290 PrPreprocessInputFile (
 291     void)
 292 {
 293     UINT32                  Offset;
 294     char                    *Token;
 295     char                    *ReplaceString;
 296     PR_DEFINE_INFO          *DefineInfo;
 297     ACPI_SIZE               TokenOffset;
 298     char                    *Next;
 299     int                     OffsetAdjust;
 300 
 301 
 302     /* Scan line-by-line. Comments and blank lines are skipped by this function */
 303 
 304     while ((Offset = DtGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF)
 305     {
 306         /* Need a copy of the input line for strok() */
 307 
 308         strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
 309         Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
 310         OffsetAdjust = 0;
 311 
 312         /* All preprocessor directives must begin with '#' */
 313 
 314         if (Token && (*Token == '#'))
 315         {
 316             if (strlen (Token) == 1)
 317             {
 318                 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
 319             }
 320             else
 321             {
 322                 Token++;    /* Skip leading # */
 323             }
 324 
 325             /* Execute the directive, do not write line to output file */
 326 
 327             PrDoDirective (Token, &Next);
 328             continue;
 329         }
 330 
 331         /*
 332          * If we are currently within the part of an IF/ELSE block that is
 333          * FALSE, ignore the line and do not write it to the output file.
 334          * This continues until an #else or #endif is encountered.
 335          */
 336         if (Gbl_IgnoringThisCodeBlock)
 337         {
 338             continue;
 339         }
 340 
 341         /* Match and replace all #defined names within this source line */
 342 
 343         while (Token)
 344         {
 345             DefineInfo = PrMatchDefine (Token);
 346             if (DefineInfo)
 347             {
 348                 if (DefineInfo->Body)
 349                 {
 350                     /* This is a macro */
 351 
 352                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 353                         "Matched Macro: %s->%s\n",
 354                         Gbl_CurrentLineNumber, DefineInfo->Identifier,
 355                         DefineInfo->Replacement);
 356 
 357                     PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
 358                         DefineInfo, &Next);
 359                 }
 360                 else
 361                 {
 362                     ReplaceString = DefineInfo->Replacement;
 363 
 364                     /* Replace the name in the original line buffer */
 365 
 366                     TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
 367                     PrReplaceData (
 368                         &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
 369                         ReplaceString, strlen (ReplaceString));
 370 
 371                     /* Adjust for length difference between old and new name length */
 372 
 373                     OffsetAdjust += strlen (ReplaceString) - strlen (Token);
 374 
 375                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 376                         "Matched #define: %s->%s\n",
 377                         Gbl_CurrentLineNumber, Token,
 378                         *ReplaceString ? ReplaceString : "(NULL STRING)");
 379                 }
 380             }
 381 
 382             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
 383         }
 384 
 385 #if 0
 386 /* Line prefix */
 387         FlPrintFile (ASL_FILE_PREPROCESSOR, "/* %14s  %.5u  i:%.5u */ ",
 388             Gbl_Files[ASL_FILE_INPUT].Filename,
 389             Gbl_CurrentLineNumber, Gbl_PreprocessorLineNumber);
 390 #endif
 391 
 392         /*
 393          * Emit a #line directive if necessary, to keep the line numbers in
 394          * the (.i) file synchronized with the original source code file, so
 395          * that the correct line number appears in any error messages
 396          * generated by the actual compiler.
 397          */
 398         if (Gbl_CurrentLineNumber > (Gbl_PreviousLineNumber + 1))
 399         {
 400             FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u\n",
 401                 Gbl_CurrentLineNumber);
 402         }
 403 
 404         Gbl_PreviousLineNumber = Gbl_CurrentLineNumber;
 405         Gbl_PreprocessorLineNumber++;
 406 
 407         /*
 408          * Now we can write the possibly modified source line to the
 409          * preprocessor (.i) file
 410          */
 411         FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
 412             strlen (Gbl_CurrentLineBuffer));
 413     }
 414 }
 415 
 416 
 417 /*******************************************************************************
 418  *
 419  * FUNCTION:    PrDoDirective
 420  *
 421  * PARAMETERS:  Directive               - Pointer to directive name token
 422  *              Next                    - "Next" buffer from GetNextToken
 423  *
 424  * RETURN:      None.
 425  *
 426  * DESCRIPTION: Main processing for all preprocessor directives
 427  *
 428  ******************************************************************************/
 429 
 430 static void
 431 PrDoDirective (
 432     char                    *DirectiveToken,
 433     char                    **Next)
 434 {
 435     char                    *Token = Gbl_MainTokenBuffer;
 436     char                    *Token2;
 437     char                    *End;
 438     UINT64                  Value;
 439     ACPI_SIZE               TokenOffset;
 440     int                     Directive;
 441     ACPI_STATUS             Status;
 442 
 443 
 444     if (!DirectiveToken)
 445     {
 446         goto SyntaxError;
 447     }
 448 
 449     Directive = PrMatchDirective (DirectiveToken);
 450     if (Directive == ASL_DIRECTIVE_NOT_FOUND)
 451     {
 452         PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
 453             THIS_TOKEN_OFFSET (DirectiveToken));
 454 
 455         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 456             "#%s: Unknown directive\n",
 457             Gbl_CurrentLineNumber, DirectiveToken);
 458         return;
 459     }
 460 
 461     /*
 462      * If we are currently ignoring this block and we encounter a #else or
 463      * #elif, we must ignore their blocks also if the parent block is also
 464      * being ignored.
 465      */
 466     if (Gbl_IgnoringThisCodeBlock)
 467     {
 468         switch (Directive)
 469         {
 470         case PR_DIRECTIVE_ELSE:
 471         case PR_DIRECTIVE_ELIF:
 472 
 473             if (Gbl_DirectiveStack && Gbl_DirectiveStack->IgnoringThisCodeBlock)
 474             {
 475                 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
 476                 return;
 477             }
 478             break;
 479 
 480         default:
 481             break;
 482         }
 483     }
 484 
 485     /*
 486      * Need to always check for #else, #elif, #endif regardless of
 487      * whether we are ignoring the current code block, since these
 488      * are conditional code block terminators.
 489      */
 490     switch (Directive)
 491     {
 492     case PR_DIRECTIVE_ELSE:
 493 
 494         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
 495         PrDbgPrint ("Executing", "else block");
 496         return;
 497 
 498     case PR_DIRECTIVE_ELIF:
 499 
 500         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
 501         Directive = PR_DIRECTIVE_IF;
 502 
 503         if (Gbl_IgnoringThisCodeBlock == TRUE)
 504         {
 505             /* Not executing the ELSE part -- all done here */
 506             PrDbgPrint ("Ignoring", "elif block");
 507             return;
 508         }
 509 
 510         /*
 511          * After this, we will execute the IF part further below.
 512          * First, however, pop off the original #if directive.
 513          */
 514         if (ACPI_FAILURE (PrPopDirective ()))
 515         {
 516             PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
 517                 THIS_TOKEN_OFFSET (DirectiveToken));
 518         }
 519 
 520         PrDbgPrint ("Executing", "elif block");
 521         break;
 522 
 523     case PR_DIRECTIVE_ENDIF:
 524 
 525         PrDbgPrint ("Executing", "endif");
 526 
 527         /* Pop the owning #if/#ifdef/#ifndef */
 528 
 529         if (ACPI_FAILURE (PrPopDirective ()))
 530         {
 531             PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
 532                 THIS_TOKEN_OFFSET (DirectiveToken));
 533         }
 534         return;
 535 
 536     default:
 537         break;
 538     }
 539 
 540     /* Most directives have at least one argument */
 541 
 542     if (Gbl_DirectiveInfo[Directive].ArgCount == 1)
 543     {
 544         Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
 545         if (!Token)
 546         {
 547             goto SyntaxError;
 548         }
 549     }
 550 
 551     /*
 552      * At this point, if we are ignoring the current code block,
 553      * do not process any more directives (i.e., ignore them also.)
 554      * For "if" style directives, open/push a new block anyway. We
 555      * must do this to keep track of #endif directives
 556      */
 557     if (Gbl_IgnoringThisCodeBlock)
 558     {
 559         switch (Directive)
 560         {
 561         case PR_DIRECTIVE_IF:
 562         case PR_DIRECTIVE_IFDEF:
 563         case PR_DIRECTIVE_IFNDEF:
 564 
 565             PrPushDirective (Directive, Token);
 566             PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
 567             break;
 568 
 569         default:
 570             break;
 571         }
 572 
 573         return;
 574     }
 575 
 576     /*
 577      * Execute the directive
 578      */
 579     PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
 580 
 581     switch (Directive)
 582     {
 583     case PR_DIRECTIVE_IF:
 584 
 585         TokenOffset = Token - Gbl_MainTokenBuffer;
 586 
 587         /* Need to expand #define macros in the expression string first */
 588 
 589         Status = PrResolveIntegerExpression (
 590             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
 591         if (ACPI_FAILURE (Status))
 592         {
 593             return;
 594         }
 595 
 596         PrPushDirective (Directive, Token);
 597         if (!Value)
 598         {
 599             Gbl_IgnoringThisCodeBlock = TRUE;
 600         }
 601 
 602         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 603             "Resolved #if: %8.8X%8.8X %s\n",
 604             Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
 605             Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
 606         break;
 607 
 608     case PR_DIRECTIVE_IFDEF:
 609 
 610         PrPushDirective (Directive, Token);
 611         if (!PrMatchDefine (Token))
 612         {
 613             Gbl_IgnoringThisCodeBlock = TRUE;
 614         }
 615 
 616         PrDbgPrint ("Evaluated", "ifdef");
 617         break;
 618 
 619     case PR_DIRECTIVE_IFNDEF:
 620 
 621         PrPushDirective (Directive, Token);
 622         if (PrMatchDefine (Token))
 623         {
 624             Gbl_IgnoringThisCodeBlock = TRUE;
 625         }
 626 
 627         PrDbgPrint ("Evaluated", "ifndef");
 628         break;
 629 
 630     case PR_DIRECTIVE_DEFINE:
 631         /*
 632          * By definition, if first char after the name is a paren,
 633          * this is a function macro.
 634          */
 635         TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
 636         if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
 637         {
 638 #ifndef MACROS_SUPPORTED
 639             AcpiOsPrintf ("%s ERROR - line %u: #define macros are not supported yet\n",
 640                 Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber);
 641             exit(1);
 642 #else
 643             PrAddMacro (Token, Next);
 644 #endif
 645         }
 646         else
 647         {
 648             /* Use the remainder of the line for the #define */
 649 
 650             Token2 = *Next;
 651             if (Token2)
 652             {
 653                 while ((*Token2 == ' ') || (*Token2 == '\t'))
 654                 {
 655                     Token2++;
 656                 }
 657                 End = Token2;
 658                 while (*End != '\n')
 659                 {
 660                     End++;
 661                 }
 662                 *End = 0;
 663             }
 664             else
 665             {
 666                 Token2 = "";
 667             }
 668 #if 0
 669             Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
 670             if (!Token2)
 671             {
 672                 Token2 = "";
 673             }
 674 #endif
 675             DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 676                 "New #define: %s->%s\n",
 677                 Gbl_CurrentLineNumber, Token, Token2);
 678 
 679             PrAddDefine (Token, Token2, FALSE);
 680         }
 681         break;
 682 
 683     case PR_DIRECTIVE_ERROR:
 684 
 685         /* Note: No macro expansion */
 686 
 687         PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
 688             THIS_TOKEN_OFFSET (Token));
 689 
 690         Gbl_SourceLine = 0;
 691         Gbl_NextError = Gbl_ErrorLog;
 692         CmCleanupAndExit ();
 693         exit(1);
 694 
 695     case PR_DIRECTIVE_INCLUDE:
 696 
 697         Token = PrGetNextToken (NULL, " \"<>", Next);
 698         if (!Token)
 699         {
 700             goto SyntaxError;
 701         }
 702 
 703         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 704             "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
 705             Token, Gbl_CurrentLineNumber);
 706 
 707         PrOpenIncludeFile (Token);
 708         break;
 709 
 710     case PR_DIRECTIVE_LINE:
 711 
 712         TokenOffset = Token - Gbl_MainTokenBuffer;
 713 
 714         Status = PrResolveIntegerExpression (
 715             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
 716         if (ACPI_FAILURE (Status))
 717         {
 718             return;
 719         }
 720 
 721         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 722             "User #line invocation %s\n", Gbl_CurrentLineNumber,
 723             Token);
 724 
 725         /* Update local line numbers */
 726 
 727         Gbl_CurrentLineNumber = (UINT32) Value;
 728         Gbl_PreviousLineNumber = 0;
 729 
 730         /* Emit #line into the preprocessor file */
 731 
 732         FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
 733             Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
 734         break;
 735 
 736     case PR_DIRECTIVE_PRAGMA:
 737 
 738         if (!strcmp (Token, "disable"))
 739         {
 740             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
 741             if (!Token)
 742             {
 743                 goto SyntaxError;
 744             }
 745 
 746             TokenOffset = Token - Gbl_MainTokenBuffer;
 747             AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
 748         }
 749         else if (!strcmp (Token, "message"))
 750         {
 751             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
 752             if (!Token)
 753             {
 754                 goto SyntaxError;
 755             }
 756 
 757             TokenOffset = Token - Gbl_MainTokenBuffer;
 758             AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
 759         }
 760         else
 761         {
 762             PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
 763                 THIS_TOKEN_OFFSET (Token));
 764             return;
 765         }
 766 
 767         break;
 768 
 769     case PR_DIRECTIVE_UNDEF:
 770 
 771         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 772             "#undef: %s\n", Gbl_CurrentLineNumber, Token);
 773 
 774         PrRemoveDefine (Token);
 775         break;
 776 
 777     case PR_DIRECTIVE_WARNING:
 778 
 779         PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
 780             THIS_TOKEN_OFFSET (Token));
 781         break;
 782 
 783     default:
 784 
 785         /* Should never get here */
 786         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
 787             "Unrecognized directive: %u\n",
 788             Gbl_CurrentLineNumber, Directive);
 789         break;
 790     }
 791 
 792     return;
 793 
 794 SyntaxError:
 795 
 796     PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
 797         THIS_TOKEN_OFFSET (DirectiveToken));
 798     return;
 799 }
 800 
 801 
 802 /*******************************************************************************
 803  *
 804  * FUNCTION:    PrMatchDirective
 805  *
 806  * PARAMETERS:  Directive           - Pointer to directive name token
 807  *
 808  * RETURN:      Index into command array, -1 if not found
 809  *
 810  * DESCRIPTION: Lookup the incoming directive in the known directives table.
 811  *
 812  ******************************************************************************/
 813 
 814 static int
 815 PrMatchDirective (
 816     char                    *Directive)
 817 {
 818     int                     i;
 819 
 820 
 821     if (!Directive || Directive[0] == 0)
 822     {
 823         return (ASL_DIRECTIVE_NOT_FOUND);
 824     }
 825 
 826     for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
 827     {
 828         if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
 829         {
 830             return (i);
 831         }
 832     }
 833 
 834     return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
 835 }
 836 
 837 
 838 /*******************************************************************************
 839  *
 840  * FUNCTION:    PrPushDirective
 841  *
 842  * PARAMETERS:  Directive           - Encoded directive ID
 843  *              Argument            - String containing argument to the
 844  *                                    directive
 845  *
 846  * RETURN:      None
 847  *
 848  * DESCRIPTION: Push an item onto the directive stack. Used for processing
 849  *              nested #if/#else type conditional compilation directives.
 850  *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
 851  *              a block.
 852  *
 853  ******************************************************************************/
 854 
 855 static void
 856 PrPushDirective (
 857     int                     Directive,
 858     char                    *Argument)
 859 {
 860     DIRECTIVE_INFO          *Info;
 861 
 862 
 863     /* Allocate and populate a stack info item */
 864 
 865     Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
 866 
 867     Info->Next = Gbl_DirectiveStack;
 868     Info->Directive = Directive;
 869     Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
 870     strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
 871 
 872     DbgPrint (ASL_DEBUG_OUTPUT,
 873         "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
 874         Gbl_CurrentLineNumber, Gbl_IfDepth,
 875         Gbl_IgnoringThisCodeBlock ? "I" : "E",
 876         Gbl_IfDepth * 4, " ",
 877         Gbl_DirectiveInfo[Directive].Name,
 878         Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
 879 
 880     /* Push new item */
 881 
 882     Gbl_DirectiveStack = Info;
 883     Gbl_IfDepth++;
 884 }
 885 
 886 
 887 /*******************************************************************************
 888  *
 889  * FUNCTION:    PrPopDirective
 890  *
 891  * PARAMETERS:  None
 892  *
 893  * RETURN:      Status. Error if the stack is empty.
 894  *
 895  * DESCRIPTION: Pop an item off the directive stack. Used for processing
 896  *              nested #if/#else type conditional compilation directives.
 897  *              Specifically: Used on detection of #elif and #endif to remove
 898  *              the original #if/#ifdef/#ifndef from the stack and close
 899  *              the block.
 900  *
 901  ******************************************************************************/
 902 
 903 static ACPI_STATUS
 904 PrPopDirective (
 905     void)
 906 {
 907     DIRECTIVE_INFO          *Info;
 908 
 909 
 910     /* Check for empty stack */
 911 
 912     Info = Gbl_DirectiveStack;
 913     if (!Info)
 914     {
 915         return (AE_ERROR);
 916     }
 917 
 918     /* Pop one item, keep globals up-to-date */
 919 
 920     Gbl_IfDepth--;
 921     Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
 922     Gbl_DirectiveStack = Info->Next;
 923 
 924     DbgPrint (ASL_DEBUG_OUTPUT,
 925         "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
 926         Gbl_CurrentLineNumber, Gbl_IfDepth,
 927         Gbl_IgnoringThisCodeBlock ? "I" : "E",
 928         Gbl_IfDepth * 4, " ",
 929         Gbl_DirectiveInfo[Info->Directive].Name,
 930         Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
 931 
 932     ACPI_FREE (Info);
 933     return (AE_OK);
 934 }
 935 
 936 
 937 /*******************************************************************************
 938  *
 939  * FUNCTION:    PrDbgPrint
 940  *
 941  * PARAMETERS:  Action              - Action being performed
 942  *              DirectiveName       - Directive being processed
 943  *
 944  * RETURN:      None
 945  *
 946  * DESCRIPTION: Special debug print for directive processing.
 947  *
 948  ******************************************************************************/
 949 
 950 static void
 951 PrDbgPrint (
 952     char                    *Action,
 953     char                    *DirectiveName)
 954 {
 955 
 956     DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
 957         "%*s %s #%s, Depth %u\n",
 958         Gbl_CurrentLineNumber, Gbl_IfDepth,
 959         Gbl_IgnoringThisCodeBlock ? "I" : "E",
 960         Gbl_IfDepth * 4, " ",
 961         Action, DirectiveName, Gbl_IfDepth);
 962 }