Home | History | Annotate | Line # | Download | only in compiler
prscan.c revision 1.1.1.6
      1 /******************************************************************************
      2  *
      3  * Module Name: prscan - Preprocessor start-up and file scan module
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2016, 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_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