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