Home | History | Annotate | Line # | Download | only in compiler
prscan.c revision 1.1.1.5
      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_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 &&
    503                 Gbl_DirectiveStack->IgnoringThisCodeBlock)
    504             {
    505                 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
    506                 return;
    507             }
    508             break;
    509 
    510         default:
    511             break;
    512         }
    513     }
    514 
    515     /*
    516      * Need to always check for #else, #elif, #endif regardless of
    517      * whether we are ignoring the current code block, since these
    518      * are conditional code block terminators.
    519      */
    520     switch (Directive)
    521     {
    522     case PR_DIRECTIVE_ELSE:
    523 
    524         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
    525         PrDbgPrint ("Executing", "else block");
    526         return;
    527 
    528     case PR_DIRECTIVE_ELIF:
    529 
    530         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
    531         Directive = PR_DIRECTIVE_IF;
    532 
    533         if (Gbl_IgnoringThisCodeBlock == TRUE)
    534         {
    535             /* Not executing the ELSE part -- all done here */
    536             PrDbgPrint ("Ignoring", "elif block");
    537             return;
    538         }
    539 
    540         /*
    541          * After this, we will execute the IF part further below.
    542          * First, however, pop off the original #if directive.
    543          */
    544         if (ACPI_FAILURE (PrPopDirective ()))
    545         {
    546             PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
    547                 THIS_TOKEN_OFFSET (DirectiveToken));
    548         }
    549 
    550         PrDbgPrint ("Executing", "elif block");
    551         break;
    552 
    553     case PR_DIRECTIVE_ENDIF:
    554 
    555         PrDbgPrint ("Executing", "endif");
    556 
    557         /* Pop the owning #if/#ifdef/#ifndef */
    558 
    559         if (ACPI_FAILURE (PrPopDirective ()))
    560         {
    561             PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
    562                 THIS_TOKEN_OFFSET (DirectiveToken));
    563         }
    564         return;
    565 
    566     default:
    567         break;
    568     }
    569 
    570     /* Most directives have at least one argument */
    571 
    572     if (Gbl_DirectiveInfo[Directive].ArgCount >= 1)
    573     {
    574         Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
    575         if (!Token)
    576         {
    577             goto SyntaxError;
    578         }
    579     }
    580 
    581     if (Gbl_DirectiveInfo[Directive].ArgCount >= 2)
    582     {
    583         Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
    584         if (!Token2)
    585         {
    586             goto SyntaxError;
    587         }
    588     }
    589 
    590     /*
    591      * At this point, if we are ignoring the current code block,
    592      * do not process any more directives (i.e., ignore them also.)
    593      * For "if" style directives, open/push a new block anyway. We
    594      * must do this to keep track of #endif directives
    595      */
    596     if (Gbl_IgnoringThisCodeBlock)
    597     {
    598         switch (Directive)
    599         {
    600         case PR_DIRECTIVE_IF:
    601         case PR_DIRECTIVE_IFDEF:
    602         case PR_DIRECTIVE_IFNDEF:
    603 
    604             PrPushDirective (Directive, Token);
    605             PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
    606             break;
    607 
    608         default:
    609             break;
    610         }
    611 
    612         return;
    613     }
    614 
    615     /*
    616      * Execute the directive
    617      */
    618     PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
    619 
    620     switch (Directive)
    621     {
    622     case PR_DIRECTIVE_IF:
    623 
    624         TokenOffset = Token - Gbl_MainTokenBuffer;
    625 
    626         /* Need to expand #define macros in the expression string first */
    627 
    628         Status = PrResolveIntegerExpression (
    629             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
    630         if (ACPI_FAILURE (Status))
    631         {
    632             return;
    633         }
    634 
    635         PrPushDirective (Directive, Token);
    636         if (!Value)
    637         {
    638             Gbl_IgnoringThisCodeBlock = TRUE;
    639         }
    640 
    641         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
    642             "Resolved #if: %8.8X%8.8X %s\n",
    643             Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
    644             Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
    645         break;
    646 
    647     case PR_DIRECTIVE_IFDEF:
    648 
    649         PrPushDirective (Directive, Token);
    650         if (!PrMatchDefine (Token))
    651         {
    652             Gbl_IgnoringThisCodeBlock = TRUE;
    653         }
    654 
    655         PrDbgPrint ("Evaluated", "ifdef");
    656         break;
    657 
    658     case PR_DIRECTIVE_IFNDEF:
    659 
    660         PrPushDirective (Directive, Token);
    661         if (PrMatchDefine (Token))
    662         {
    663             Gbl_IgnoringThisCodeBlock = TRUE;
    664         }
    665 
    666         PrDbgPrint ("Evaluated", "ifndef");
    667         break;
    668 
    669     case PR_DIRECTIVE_DEFINE:
    670         /*
    671          * By definition, if first char after the name is a paren,
    672          * this is a function macro.
    673          */
    674         TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
    675         if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
    676         {
    677 #ifndef MACROS_SUPPORTED
    678             AcpiOsPrintf (
    679                 "%s ERROR - line %u: #define macros are not supported yet\n",
    680                 Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber);
    681             exit(1);
    682 #else
    683             PrAddMacro (Token, Next);
    684 #endif
    685         }
    686         else
    687         {
    688             /* Use the remainder of the line for the #define */
    689 
    690             Token2 = *Next;
    691             if (Token2)
    692             {
    693                 while ((*Token2 == ' ') || (*Token2 == '\t'))
    694                 {
    695                     Token2++;
    696                 }
    697 
    698                 End = Token2;
    699                 while (*End != '\n')
    700                 {
    701                     End++;
    702                 }
    703 
    704                 *End = 0;
    705             }
    706             else
    707             {
    708                 Token2 = "";
    709             }
    710 #if 0
    711             Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
    712             if (!Token2)
    713             {
    714                 Token2 = "";
    715             }
    716 #endif
    717             DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
    718                 "New #define: %s->%s\n",
    719                 Gbl_LogicalLineNumber, Token, Token2);
    720 
    721             PrAddDefine (Token, Token2, FALSE);
    722         }
    723         break;
    724 
    725     case PR_DIRECTIVE_ERROR:
    726 
    727         /* Note: No macro expansion */
    728 
    729         PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
    730             THIS_TOKEN_OFFSET (Token));
    731 
    732         Gbl_SourceLine = 0;
    733         Gbl_NextError = Gbl_ErrorLog;
    734         CmCleanupAndExit ();
    735         exit(1);
    736 
    737     case PR_DIRECTIVE_INCLUDE:
    738 
    739         Token = PrGetNextToken (NULL, " \"<>", Next);
    740         if (!Token)
    741         {
    742             goto SyntaxError;
    743         }
    744 
    745         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
    746             "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
    747             Token, Gbl_CurrentLineNumber);
    748 
    749         PrDoIncludeFile (Token);
    750         break;
    751 
    752     case PR_DIRECTIVE_INCLUDEBUFFER:
    753 
    754         Token = PrGetNextToken (NULL, " \"<>", Next);
    755         if (!Token)
    756         {
    757             goto SyntaxError;
    758         }
    759 
    760         Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
    761         if (!Token2)
    762         {
    763             goto SyntaxError;
    764         }
    765 
    766         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
    767             "Start #includebuffer input from file \"%s\", buffer name %s\n",
    768             Gbl_CurrentLineNumber, Token, Token2);
    769 
    770         PrDoIncludeBuffer (Token, Token2);
    771         break;
    772 
    773     case PR_DIRECTIVE_LINE:
    774 
    775         TokenOffset = Token - Gbl_MainTokenBuffer;
    776 
    777         Status = PrResolveIntegerExpression (
    778             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
    779         if (ACPI_FAILURE (Status))
    780         {
    781             return;
    782         }
    783 
    784         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
    785             "User #line invocation %s\n", Gbl_CurrentLineNumber,
    786             Token);
    787 
    788         Gbl_CurrentLineNumber = (UINT32) Value;
    789 
    790         /* Emit #line into the preprocessor file */
    791 
    792         FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
    793             Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
    794         break;
    795 
    796     case PR_DIRECTIVE_PRAGMA:
    797 
    798         if (!strcmp (Token, "disable"))
    799         {
    800             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
    801             if (!Token)
    802             {
    803                 goto SyntaxError;
    804             }
    805 
    806             TokenOffset = Token - Gbl_MainTokenBuffer;
    807             AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
    808         }
    809         else if (!strcmp (Token, "message"))
    810         {
    811             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
    812             if (!Token)
    813             {
    814                 goto SyntaxError;
    815             }
    816 
    817             TokenOffset = Token - Gbl_MainTokenBuffer;
    818             AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
    819         }
    820         else
    821         {
    822             PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
    823                 THIS_TOKEN_OFFSET (Token));
    824             return;
    825         }
    826 
    827         break;
    828 
    829     case PR_DIRECTIVE_UNDEF:
    830 
    831         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
    832             "#undef: %s\n", Gbl_CurrentLineNumber, Token);
    833 
    834         PrRemoveDefine (Token);
    835         break;
    836 
    837     case PR_DIRECTIVE_WARNING:
    838 
    839         PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
    840             THIS_TOKEN_OFFSET (Token));
    841 
    842         Gbl_SourceLine = 0;
    843         Gbl_NextError = Gbl_ErrorLog;
    844         break;
    845 
    846     default:
    847 
    848         /* Should never get here */
    849         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
    850             "Unrecognized directive: %u\n",
    851             Gbl_CurrentLineNumber, Directive);
    852         break;
    853     }
    854 
    855     return;
    856 
    857 SyntaxError:
    858 
    859     PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
    860         THIS_TOKEN_OFFSET (DirectiveToken));
    861     return;
    862 }
    863 
    864 
    865 /*******************************************************************************
    866  *
    867  * FUNCTION:    PrGetNextLine, PrGetNextLineInit
    868  *
    869  * PARAMETERS:  Handle              - Open file handle for the source file
    870  *
    871  * RETURN:      Status of the GetLine operation:
    872  *              AE_OK               - Normal line, OK status
    873  *              ASL_WITHIN_COMMENT  - Line is part of a multi-line 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             return (ASL_EOF);
    923         }
    924 
    925         /* Update state machine as necessary */
    926 
    927         switch (AcpiGbl_LineScanState)
    928         {
    929         case PR_NORMAL_TEXT:
    930 
    931             /* Check for multi-line comment start */
    932 
    933             if ((PreviousChar == '/') && (c == '*'))
    934             {
    935                 AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT;
    936             }
    937 
    938             /* Check for single-line comment start */
    939 
    940             else if ((PreviousChar == '/') && (c == '/'))
    941             {
    942                 AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT;
    943             }
    944 
    945             /* Check for quoted string start */
    946 
    947             else if (PreviousChar == '"')
    948             {
    949                 AcpiGbl_LineScanState = PR_QUOTED_STRING;
    950             }
    951             break;
    952 
    953         case PR_QUOTED_STRING:
    954 
    955             if (PreviousChar == '"')
    956             {
    957                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
    958             }
    959             break;
    960 
    961         case PR_MULTI_LINE_COMMENT:
    962 
    963             /* Check for multi-line comment end */
    964 
    965             if ((PreviousChar == '*') && (c == '/'))
    966             {
    967                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
    968             }
    969             break;
    970 
    971         case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */
    972         default:
    973             break;
    974         }
    975 
    976         /* Always copy the character into line buffer */
    977 
    978         Gbl_CurrentLineBuffer[i] = (char) c;
    979         i++;
    980 
    981         /* Always exit on end-of-line */
    982 
    983         if (c == '\n')
    984         {
    985             /* Handle multi-line comments */
    986 
    987             if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT)
    988             {
    989                 return (ASL_WITHIN_COMMENT);
    990             }
    991 
    992             /* End of single-line comment */
    993 
    994             if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT)
    995             {
    996                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
    997                 return (AE_OK);
    998             }
    999 
   1000             /* Blank line */
   1001 
   1002             if (i == 1)
   1003             {
   1004                 return (ASL_BLANK_LINE);
   1005             }
   1006 
   1007             return (AE_OK);
   1008         }
   1009     }
   1010 }
   1011 
   1012 
   1013 /*******************************************************************************
   1014  *
   1015  * FUNCTION:    PrMatchDirective
   1016  *
   1017  * PARAMETERS:  Directive           - Pointer to directive name token
   1018  *
   1019  * RETURN:      Index into command array, -1 if not found
   1020  *
   1021  * DESCRIPTION: Lookup the incoming directive in the known directives table.
   1022  *
   1023  ******************************************************************************/
   1024 
   1025 static int
   1026 PrMatchDirective (
   1027     char                    *Directive)
   1028 {
   1029     int                     i;
   1030 
   1031 
   1032     if (!Directive || Directive[0] == 0)
   1033     {
   1034         return (ASL_DIRECTIVE_NOT_FOUND);
   1035     }
   1036 
   1037     for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
   1038     {
   1039         if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
   1040         {
   1041             return (i);
   1042         }
   1043     }
   1044 
   1045     return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
   1046 }
   1047 
   1048 
   1049 /*******************************************************************************
   1050  *
   1051  * FUNCTION:    PrPushDirective
   1052  *
   1053  * PARAMETERS:  Directive           - Encoded directive ID
   1054  *              Argument            - String containing argument to the
   1055  *                                    directive
   1056  *
   1057  * RETURN:      None
   1058  *
   1059  * DESCRIPTION: Push an item onto the directive stack. Used for processing
   1060  *              nested #if/#else type conditional compilation directives.
   1061  *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
   1062  *              a block.
   1063  *
   1064  ******************************************************************************/
   1065 
   1066 static void
   1067 PrPushDirective (
   1068     int                     Directive,
   1069     char                    *Argument)
   1070 {
   1071     DIRECTIVE_INFO          *Info;
   1072 
   1073 
   1074     /* Allocate and populate a stack info item */
   1075 
   1076     Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
   1077 
   1078     Info->Next = Gbl_DirectiveStack;
   1079     Info->Directive = Directive;
   1080     Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
   1081     strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
   1082 
   1083     DbgPrint (ASL_DEBUG_OUTPUT,
   1084         "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
   1085         Gbl_CurrentLineNumber, Gbl_IfDepth,
   1086         Gbl_IgnoringThisCodeBlock ? "I" : "E",
   1087         Gbl_IfDepth * 4, " ",
   1088         Gbl_DirectiveInfo[Directive].Name,
   1089         Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
   1090 
   1091     /* Push new item */
   1092 
   1093     Gbl_DirectiveStack = Info;
   1094     Gbl_IfDepth++;
   1095 }
   1096 
   1097 
   1098 /*******************************************************************************
   1099  *
   1100  * FUNCTION:    PrPopDirective
   1101  *
   1102  * PARAMETERS:  None
   1103  *
   1104  * RETURN:      Status. Error if the stack is empty.
   1105  *
   1106  * DESCRIPTION: Pop an item off the directive stack. Used for processing
   1107  *              nested #if/#else type conditional compilation directives.
   1108  *              Specifically: Used on detection of #elif and #endif to remove
   1109  *              the original #if/#ifdef/#ifndef from the stack and close
   1110  *              the block.
   1111  *
   1112  ******************************************************************************/
   1113 
   1114 static ACPI_STATUS
   1115 PrPopDirective (
   1116     void)
   1117 {
   1118     DIRECTIVE_INFO          *Info;
   1119 
   1120 
   1121     /* Check for empty stack */
   1122 
   1123     Info = Gbl_DirectiveStack;
   1124     if (!Info)
   1125     {
   1126         return (AE_ERROR);
   1127     }
   1128 
   1129     /* Pop one item, keep globals up-to-date */
   1130 
   1131     Gbl_IfDepth--;
   1132     Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
   1133     Gbl_DirectiveStack = Info->Next;
   1134 
   1135     DbgPrint (ASL_DEBUG_OUTPUT,
   1136         "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
   1137         Gbl_CurrentLineNumber, Gbl_IfDepth,
   1138         Gbl_IgnoringThisCodeBlock ? "I" : "E",
   1139         Gbl_IfDepth * 4, " ",
   1140         Gbl_DirectiveInfo[Info->Directive].Name,
   1141         Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
   1142 
   1143     ACPI_FREE (Info);
   1144     return (AE_OK);
   1145 }
   1146 
   1147 
   1148 /*******************************************************************************
   1149  *
   1150  * FUNCTION:    PrDbgPrint
   1151  *
   1152  * PARAMETERS:  Action              - Action being performed
   1153  *              DirectiveName       - Directive being processed
   1154  *
   1155  * RETURN:      None
   1156  *
   1157  * DESCRIPTION: Special debug print for directive processing.
   1158  *
   1159  ******************************************************************************/
   1160 
   1161 static void
   1162 PrDbgPrint (
   1163     char                    *Action,
   1164     char                    *DirectiveName)
   1165 {
   1166 
   1167     DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
   1168         "%*s %s #%s, IfDepth %u\n",
   1169         Gbl_CurrentLineNumber, Gbl_IfDepth,
   1170         Gbl_IgnoringThisCodeBlock ? "I" : "E",
   1171         Gbl_IfDepth * 4, " ",
   1172         Action, DirectiveName, Gbl_IfDepth);
   1173 }
   1174 
   1175 
   1176 /*******************************************************************************
   1177  *
   1178  * FUNCTION:    PrDoIncludeFile
   1179  *
   1180  * PARAMETERS:  Pathname                - Name of the input file
   1181  *
   1182  * RETURN:      None.
   1183  *
   1184  * DESCRIPTION: Open an include file, from #include.
   1185  *
   1186  ******************************************************************************/
   1187 
   1188 static void
   1189 PrDoIncludeFile (
   1190     char                    *Pathname)
   1191 {
   1192     char                    *FullPathname;
   1193 
   1194 
   1195     (void) PrOpenIncludeFile (Pathname, "r", &FullPathname);
   1196 }
   1197 
   1198 
   1199 /*******************************************************************************
   1200  *
   1201  * FUNCTION:    PrDoIncludeBuffer
   1202  *
   1203  * PARAMETERS:  Pathname                - Name of the input binary file
   1204  *              BufferName              - ACPI namepath of the buffer
   1205  *
   1206  * RETURN:      None.
   1207  *
   1208  * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents
   1209  *              of the file are emitted into the buffer object as ascii
   1210  *              hex data. From #includebuffer.
   1211  *
   1212  ******************************************************************************/
   1213 
   1214 static void
   1215 PrDoIncludeBuffer (
   1216     char                    *Pathname,
   1217     char                    *BufferName)
   1218 {
   1219     char                    *FullPathname;
   1220     FILE                    *BinaryBufferFile;
   1221     UINT32                  i = 0;
   1222     UINT8                   c;
   1223 
   1224 
   1225     BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname);
   1226     if (!BinaryBufferFile)
   1227     {
   1228         return;
   1229     }
   1230 
   1231     /* Emit "Name (XXXX, Buffer() {" header */
   1232 
   1233     FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName);
   1234 
   1235     /* Dump the entire file in ascii hex format */
   1236 
   1237     while (fread (&c, 1, 1, BinaryBufferFile))
   1238     {
   1239         if (!(i % 8))
   1240         {
   1241             FlPrintFile (ASL_FILE_PREPROCESSOR, "\n   ", c);
   1242         }
   1243 
   1244         FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c);
   1245         i++;
   1246     }
   1247 
   1248     DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
   1249         "#includebuffer: read %u bytes from %s\n",
   1250         Gbl_CurrentLineNumber, i, FullPathname);
   1251 
   1252     /* Close the Name() operator */
   1253 
   1254     FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName);
   1255     fclose (BinaryBufferFile);
   1256 }
   1257