Home | History | Annotate | Line # | Download | only in compiler
prmacros.c revision 1.1.1.4
      1 /******************************************************************************
      2  *
      3  * Module Name: prmacros - Preprocessor #define macro support
      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 #include "aslcompiler.h"
     45 #include "dtcompiler.h"
     46 
     47 
     48 #define _COMPONENT          ASL_PREPROCESSOR
     49         ACPI_MODULE_NAME    ("prmacros")
     50 
     51 
     52 /*******************************************************************************
     53  *
     54  * FUNCTION:    PrDumpPredefinedNames
     55  *
     56  * PARAMETERS:  None
     57  *
     58  * RETURN:      None
     59  *
     60  * DESCRIPTION: Dump the list of #defines. Used as the preprocessor starts, to
     61  *              display the names that were defined on the command line.
     62  *              Debug information only.
     63  *
     64  ******************************************************************************/
     65 
     66 void
     67 PrDumpPredefinedNames (
     68     void)
     69 {
     70     PR_DEFINE_INFO          *DefineInfo;
     71 
     72 
     73     DefineInfo = Gbl_DefineList;
     74     while (DefineInfo)
     75     {
     76         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
     77             "Predefined #define: %s->%s\n",
     78             0, DefineInfo->Identifier, DefineInfo->Replacement);
     79 
     80         DefineInfo = DefineInfo->Next;
     81     }
     82 }
     83 
     84 
     85 /*******************************************************************************
     86  *
     87  * FUNCTION:    PrAddDefine
     88  *
     89  * PARAMETERS:  Identifier          - Name to be replaced
     90  *              Replacement         - Replacement for Identifier
     91  *              Persist             - Keep define across multiple compiles?
     92  *
     93  * RETURN:      A new define_info struct. NULL on error.
     94  *
     95  * DESCRIPTION: Add a new #define to the global list
     96  *
     97  ******************************************************************************/
     98 
     99 PR_DEFINE_INFO *
    100 PrAddDefine (
    101     char                    *Identifier,
    102     char                    *Replacement,
    103     BOOLEAN                 Persist)
    104 {
    105     char                    *IdentifierString;
    106     char                    *ReplacementString;
    107     PR_DEFINE_INFO          *DefineInfo;
    108 
    109 
    110     if (!Replacement)
    111     {
    112         Replacement = "";
    113     }
    114 
    115     /* Check for already-defined first */
    116 
    117     DefineInfo = PrMatchDefine (Identifier);
    118     if (DefineInfo)
    119     {
    120         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID,
    121             "#define: name already exists: %s\n",
    122             Gbl_CurrentLineNumber, Identifier);
    123 
    124         /*
    125          * Name already exists. This is only an error if the target name
    126          * is different.
    127          */
    128         if (strcmp (Replacement, DefineInfo->Replacement))
    129         {
    130             PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME,
    131                 THIS_TOKEN_OFFSET (Identifier));
    132 
    133             return (NULL);
    134         }
    135 
    136         return (DefineInfo);
    137     }
    138 
    139     /* Copy input strings */
    140 
    141     IdentifierString = UtLocalCalloc (strlen (Identifier) + 1);
    142     strcpy (IdentifierString, Identifier);
    143 
    144     ReplacementString = UtLocalCalloc (strlen (Replacement) + 1);
    145     strcpy (ReplacementString, Replacement);
    146 
    147     /* Init and link new define info struct */
    148 
    149     DefineInfo = UtLocalCalloc (sizeof (PR_DEFINE_INFO));
    150     DefineInfo->Replacement = ReplacementString;
    151     DefineInfo->Identifier = IdentifierString;
    152     DefineInfo->Persist = Persist;
    153 
    154     if (Gbl_DefineList)
    155     {
    156         Gbl_DefineList->Previous = DefineInfo;
    157     }
    158 
    159     DefineInfo->Next = Gbl_DefineList;
    160     Gbl_DefineList = DefineInfo;
    161     return (DefineInfo);
    162 }
    163 
    164 
    165 /*******************************************************************************
    166  *
    167  * FUNCTION:    PrRemoveDefine
    168  *
    169  * PARAMETERS:  DefineName          - Name of define to be removed
    170  *
    171  * RETURN:      None
    172  *
    173  * DESCRIPTION: Implements #undef. Remove a #define if found in the global
    174  *              list. No error if the target of the #undef does not exist,
    175  *              as per the C #undef definition.
    176  *
    177  ******************************************************************************/
    178 
    179 void
    180 PrRemoveDefine (
    181     char                    *DefineName)
    182 {
    183     PR_DEFINE_INFO          *DefineInfo;
    184 
    185 
    186     /* Match name and delete the node */
    187 
    188     DefineInfo = Gbl_DefineList;
    189     while (DefineInfo)
    190     {
    191         if (!strcmp (DefineName, DefineInfo->Identifier))
    192         {
    193             /* Remove from linked list */
    194 
    195             if (DefineInfo->Previous)
    196             {
    197                 (DefineInfo->Previous)->Next = DefineInfo->Next;
    198             }
    199             else
    200             {
    201                 Gbl_DefineList = DefineInfo->Next;
    202             }
    203 
    204             if (DefineInfo->Next)
    205             {
    206                 (DefineInfo->Next)->Previous = DefineInfo->Previous;
    207             }
    208 
    209             free (DefineInfo);
    210             return;
    211         }
    212 
    213         DefineInfo = DefineInfo->Next;
    214     }
    215 
    216     /*
    217      * Name was not found. By definition of #undef, this is not
    218      * an error, however.
    219      */
    220     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
    221         "#undef: could not find %s\n",
    222         Gbl_CurrentLineNumber, DefineName);
    223 }
    224 
    225 
    226 /*******************************************************************************
    227  *
    228  * FUNCTION:    PrMatchDefine
    229  *
    230  * PARAMETERS:  MatchString         - Name associated with the #define
    231  *
    232  * RETURN:      Matched string if found. NULL otherwise.
    233  *
    234  * DESCRIPTION: Find a name in global #define list
    235  *
    236  ******************************************************************************/
    237 
    238 PR_DEFINE_INFO *
    239 PrMatchDefine (
    240     char                    *MatchString)
    241 {
    242     PR_DEFINE_INFO          *DefineInfo;
    243 
    244 
    245     DefineInfo = Gbl_DefineList;
    246     while (DefineInfo)
    247     {
    248         if (!strcmp (MatchString, DefineInfo->Identifier))
    249         {
    250             return (DefineInfo);
    251         }
    252 
    253         DefineInfo = DefineInfo->Next;
    254     }
    255 
    256     return (NULL);
    257 }
    258 
    259 
    260 /*******************************************************************************
    261  *
    262  * FUNCTION:    PrAddMacro
    263  *
    264  * PARAMETERS:  Name                - Start of the macro definition
    265  *              Next                - "Next" buffer from GetNextToken
    266  *
    267  * RETURN:      None
    268  *
    269  * DESCRIPTION: Add a new macro to the list of #defines. Handles argument
    270  *              processing.
    271  *
    272  ******************************************************************************/
    273 
    274 void
    275 PrAddMacro (
    276     char                    *Name,
    277     char                    **Next)
    278 {
    279     char                    *Token = NULL;
    280     ACPI_SIZE               TokenOffset;
    281     ACPI_SIZE               MacroBodyOffset;
    282     PR_DEFINE_INFO          *DefineInfo;
    283     PR_MACRO_ARG            *Args;
    284     char                    *Body;
    285     char                    *BodyInSource;
    286     UINT32                  i;
    287     UINT16                  UseCount = 0;
    288     UINT16                  ArgCount = 0;
    289     UINT32                  Depth = 1;
    290     UINT32                  EndOfArgList;
    291     char                    BufferChar;
    292 
    293 
    294     /* Find the end of the arguments list */
    295 
    296     TokenOffset = Name - Gbl_MainTokenBuffer + strlen (Name) + 1;
    297     while (1)
    298     {
    299         BufferChar = Gbl_CurrentLineBuffer[TokenOffset];
    300         if (BufferChar == '(')
    301         {
    302             Depth++;
    303         }
    304         else if (BufferChar == ')')
    305         {
    306             Depth--;
    307         }
    308         else if (BufferChar == 0)
    309         {
    310             PrError (ASL_ERROR, ASL_MSG_MACRO_SYNTAX, TokenOffset);
    311             return;
    312         }
    313 
    314         if (Depth == 0)
    315         {
    316             /* Found arg list end */
    317 
    318             EndOfArgList = TokenOffset;
    319             break;
    320         }
    321 
    322         TokenOffset++;
    323     }
    324 
    325     /* At this point, we know that we have a reasonable argument list */
    326 
    327     Args = UtLocalCalloc (sizeof (PR_MACRO_ARG) * PR_MAX_MACRO_ARGS);
    328 
    329     /* Get the macro argument names */
    330 
    331     for (i = 0; i < PR_MAX_MACRO_ARGS; i++)
    332     {
    333         Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
    334         if (!Token)
    335         {
    336             /* This is the case for a NULL macro body */
    337 
    338             BodyInSource = "";
    339             goto AddMacroToList;
    340         }
    341 
    342         /* Don't go beyond the argument list */
    343 
    344         TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
    345         if (TokenOffset > EndOfArgList)
    346         {
    347             break;
    348         }
    349 
    350         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
    351             "Macro arg: %s \n",
    352             Gbl_CurrentLineNumber, Token);
    353 
    354         Args[i].Name = UtLocalCalloc (strlen (Token) + 1);
    355         strcpy (Args[i].Name, Token);
    356 
    357         Args[i].UseCount = 0;
    358 
    359         ArgCount++;
    360         if (ArgCount >= PR_MAX_MACRO_ARGS)
    361         {
    362             PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS, TokenOffset);
    363             goto ErrorExit;
    364         }
    365     }
    366 
    367     /* Get the macro body. Token now points to start of body */
    368 
    369     MacroBodyOffset = Token - Gbl_MainTokenBuffer;
    370 
    371     /* Match each method arg in the macro body for later use */
    372 
    373     Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
    374     while (Token)
    375     {
    376         /* Search the macro arg list for matching arg */
    377 
    378         for (i = 0; Args[i].Name && (i < PR_MAX_MACRO_ARGS); i++)
    379         {
    380             /*
    381              * Save argument offset within macro body. This is the mechanism
    382              * used to expand the macro upon invocation.
    383              *
    384              * Handles multiple instances of the same argument
    385              */
    386             if (!strcmp (Token, Args[i].Name))
    387             {
    388                 UseCount = Args[i].UseCount;
    389 
    390                 Args[i].Offset[UseCount] =
    391                     (Token - Gbl_MainTokenBuffer) - MacroBodyOffset;
    392 
    393                 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
    394                     "Macro Arg #%u: %s UseCount %u Offset %u \n",
    395                     Gbl_CurrentLineNumber, i, Token,
    396                     UseCount+1, Args[i].Offset[UseCount]);
    397 
    398                 Args[i].UseCount++;
    399                 if (Args[i].UseCount >= PR_MAX_ARG_INSTANCES)
    400                 {
    401                     PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS,
    402                         THIS_TOKEN_OFFSET (Token));
    403 
    404                     goto ErrorExit;
    405                 }
    406                 break;
    407             }
    408         }
    409 
    410         Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
    411     }
    412 
    413     BodyInSource = &Gbl_CurrentLineBuffer[MacroBodyOffset];
    414 
    415 
    416 AddMacroToList:
    417 
    418     /* Check if name is already defined first */
    419 
    420     DefineInfo = PrMatchDefine (Name);
    421     if (DefineInfo)
    422     {
    423         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
    424             "#define: macro name already exists: %s\n",
    425             Gbl_CurrentLineNumber, Name);
    426 
    427         /* Error only if not exactly the same macro */
    428 
    429         if (strcmp (DefineInfo->Body, BodyInSource) ||
    430             (DefineInfo->ArgCount != ArgCount))
    431         {
    432             PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME,
    433                 THIS_TOKEN_OFFSET (Name));
    434         }
    435 
    436         goto ErrorExit;
    437     }
    438 
    439     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
    440         "Macro body: %s \n",
    441         Gbl_CurrentLineNumber, BodyInSource);
    442 
    443     /* Add macro to the #define list */
    444 
    445     DefineInfo = PrAddDefine (Name, BodyInSource, FALSE);
    446     if (DefineInfo)
    447     {
    448         Body = UtLocalCalloc (strlen (BodyInSource) + 1);
    449         strcpy (Body, BodyInSource);
    450 
    451         DefineInfo->Body = Body;
    452         DefineInfo->Args = Args;
    453         DefineInfo->ArgCount = ArgCount;
    454     }
    455 
    456     return;
    457 
    458 
    459 ErrorExit:
    460     ACPI_FREE (Args);
    461     return;
    462 }
    463 
    464 
    465 /*******************************************************************************
    466  *
    467  * FUNCTION:    PrDoMacroInvocation
    468  *
    469  * PARAMETERS:  TokenBuffer         - Current line buffer
    470  *              MacroStart          - Start of the macro invocation within
    471  *                                    the token buffer
    472  *              DefineInfo          - Info for this macro
    473  *              Next                - "Next" buffer from GetNextToken
    474  *
    475  * RETURN:      None
    476  *
    477  * DESCRIPTION: Expand a macro invocation
    478  *
    479  ******************************************************************************/
    480 
    481 void
    482 PrDoMacroInvocation (
    483     char                    *TokenBuffer,
    484     char                    *MacroStart,
    485     PR_DEFINE_INFO          *DefineInfo,
    486     char                    **Next)
    487 {
    488     PR_MACRO_ARG            *Args;
    489     char                    *Token = NULL;
    490     UINT32                  TokenOffset;
    491     UINT32                  Length;
    492     UINT32                  i;
    493 
    494 
    495     /* Take a copy of the macro body for expansion */
    496 
    497     strcpy (Gbl_MacroTokenBuffer, DefineInfo->Body);
    498 
    499     /* Replace each argument within the prototype body */
    500 
    501     Args = DefineInfo->Args;
    502     if (!Args->Name)
    503     {
    504         /* This macro has no arguments */
    505 
    506         Token = PrGetNextToken (NULL, PR_MACRO_ARGUMENTS, Next);
    507         if (!Token)
    508         {
    509             goto BadInvocation;
    510         }
    511 
    512         TokenOffset = (MacroStart - TokenBuffer);
    513         Length = Token - MacroStart + strlen (Token) + 1;
    514 
    515         PrReplaceData (
    516             &Gbl_CurrentLineBuffer[TokenOffset], Length,
    517             Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
    518         return;
    519     }
    520 
    521     while (Args->Name)
    522     {
    523         /* Get the next argument from macro invocation */
    524 
    525         Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
    526         if (!Token)
    527         {
    528             goto BadInvocation;
    529         }
    530 
    531         /* Replace all instances of this argument */
    532 
    533         for (i = 0; i < Args->UseCount; i++)
    534         {
    535             /* Offset zero indicates "arg not used" */
    536             /* TBD: Not really needed now, with UseCount available */
    537 
    538             if (Args->Offset[i] == 0)
    539             {
    540                 break;
    541             }
    542 
    543             PrReplaceData (
    544                 &Gbl_MacroTokenBuffer[Args->Offset[i]], strlen (Args->Name),
    545                 Token, strlen (Token));
    546 
    547             DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
    548                 "ExpandArg: %s \n",
    549                 Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer);
    550         }
    551 
    552         Args++;
    553     }
    554 
    555     /* TBD: need to make sure macro was not invoked with too many arguments */
    556 
    557     if (!Token)
    558     {
    559         return;
    560     }
    561 
    562     /* Replace the entire macro invocation with the expanded macro */
    563 
    564     TokenOffset = (MacroStart - TokenBuffer);
    565     Length = Token - MacroStart + strlen (Token) + 1;
    566 
    567     PrReplaceData (
    568         &Gbl_CurrentLineBuffer[TokenOffset], Length,
    569         Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
    570 
    571     return;
    572 
    573 
    574 BadInvocation:
    575     PrError (ASL_ERROR, ASL_MSG_INVALID_INVOCATION,
    576         THIS_TOKEN_OFFSET (MacroStart));
    577 
    578     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
    579         "Bad macro invocation: %s \n",
    580         Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer);
    581     return;
    582 }
    583