prmacros.c revision 306536
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 <contrib/dev/acpica/compiler/aslcompiler.h>
45#include <contrib/dev/acpica/compiler/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
66void
67PrDumpPredefinedNames (
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
99PR_DEFINE_INFO *
100PrAddDefine (
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
179void
180PrRemoveDefine (
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
238PR_DEFINE_INFO *
239PrMatchDefine (
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
274void
275PrAddMacro (
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
416AddMacroToList:
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
459ErrorExit:
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
481void
482PrDoMacroInvocation (
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
574BadInvocation:
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