kernel: Sync ACPICA with Intel's version 20140214.
[dragonfly.git] / sys / contrib / dev / acpica / source / compiler / prmacros.c
1 /******************************************************************************
2  *
3  * Module Name: prmacros - Preprocessor #define macro support
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2014, 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] = (Token - Gbl_MainTokenBuffer) - MacroBodyOffset;
391
392                 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
393                     "Macro Arg #%u: %s UseCount %u Offset %u \n",
394                     Gbl_CurrentLineNumber, i, Token,
395                     UseCount+1, Args[i].Offset[UseCount]);
396
397                 Args[i].UseCount++;
398                 if (Args[i].UseCount >= PR_MAX_ARG_INSTANCES)
399                 {
400                     PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS,
401                         THIS_TOKEN_OFFSET (Token));
402
403                     goto ErrorExit;
404                 }
405                 break;
406             }
407         }
408
409         Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
410     }
411
412     BodyInSource = &Gbl_CurrentLineBuffer[MacroBodyOffset];
413
414
415 AddMacroToList:
416
417     /* Check if name is already defined first */
418
419     DefineInfo = PrMatchDefine (Name);
420     if (DefineInfo)
421     {
422         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
423             "#define: macro name already exists: %s\n",
424             Gbl_CurrentLineNumber, Name);
425
426         /* Error only if not exactly the same macro */
427
428         if (strcmp (DefineInfo->Body, BodyInSource) ||
429             (DefineInfo->ArgCount != ArgCount))
430         {
431             PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME,
432                 THIS_TOKEN_OFFSET (Name));
433         }
434
435         goto ErrorExit;
436     }
437
438     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
439         "Macro body: %s \n",
440         Gbl_CurrentLineNumber, BodyInSource);
441
442     /* Add macro to the #define list */
443
444     DefineInfo = PrAddDefine (Name, BodyInSource, FALSE);
445     if (DefineInfo)
446     {
447         Body = UtLocalCalloc (strlen (BodyInSource) + 1);
448         strcpy (Body, BodyInSource);
449
450         DefineInfo->Body = Body;
451         DefineInfo->Args = Args;
452         DefineInfo->ArgCount = ArgCount;
453     }
454
455     return;
456
457
458 ErrorExit:
459     ACPI_FREE (Args);
460     return;
461 }
462
463
464 /*******************************************************************************
465  *
466  * FUNCTION:    PrDoMacroInvocation
467  *
468  * PARAMETERS:  TokenBuffer         - Current line buffer
469  *              MacroStart          - Start of the macro invocation within
470  *                                    the token buffer
471  *              DefineInfo          - Info for this macro
472  *              Next                - "Next" buffer from GetNextToken
473  *
474  * RETURN:      None
475  *
476  * DESCRIPTION: Expand a macro invocation
477  *
478  ******************************************************************************/
479
480 void
481 PrDoMacroInvocation (
482     char                    *TokenBuffer,
483     char                    *MacroStart,
484     PR_DEFINE_INFO          *DefineInfo,
485     char                    **Next)
486 {
487     PR_MACRO_ARG            *Args;
488     char                    *Token = NULL;
489     UINT32                  TokenOffset;
490     UINT32                  Length;
491     UINT32                  i;
492
493
494     /* Take a copy of the macro body for expansion */
495
496     strcpy (Gbl_MacroTokenBuffer, DefineInfo->Body);
497
498     /* Replace each argument within the prototype body */
499
500     Args = DefineInfo->Args;
501     if (!Args->Name)
502     {
503         /* This macro has no arguments */
504
505         Token = PrGetNextToken (NULL, PR_MACRO_ARGUMENTS, Next);
506         if (!Token)
507         {
508             goto BadInvocation;
509         }
510
511         TokenOffset = (MacroStart - TokenBuffer);
512         Length = Token - MacroStart + strlen (Token) + 1;
513
514         PrReplaceData (
515             &Gbl_CurrentLineBuffer[TokenOffset], Length,
516             Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
517         return;
518     }
519
520     while (Args->Name)
521     {
522         /* Get the next argument from macro invocation */
523
524         Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
525         if (!Token)
526         {
527             goto BadInvocation;
528         }
529
530         /* Replace all instances of this argument */
531
532         for (i = 0; i < Args->UseCount; i++)
533         {
534             /* Offset zero indicates "arg not used" */
535             /* TBD: Not really needed now, with UseCount available */
536
537             if (Args->Offset[i] == 0)
538             {
539                 break;
540             }
541
542             PrReplaceData (
543                 &Gbl_MacroTokenBuffer[Args->Offset[i]], strlen (Args->Name),
544                 Token, strlen (Token));
545
546             DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
547                 "ExpandArg: %s \n",
548                 Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer);
549         }
550
551         Args++;
552     }
553
554     /* TBD: need to make sure macro was not invoked with too many arguments */
555
556     if (!Token)
557     {
558         return;
559     }
560
561     /* Replace the entire macro invocation with the expanded macro */
562
563     TokenOffset = (MacroStart - TokenBuffer);
564     Length = Token - MacroStart + strlen (Token) + 1;
565
566     PrReplaceData (
567         &Gbl_CurrentLineBuffer[TokenOffset], Length,
568         Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
569
570     return;
571
572
573 BadInvocation:
574     PrError (ASL_ERROR, ASL_MSG_INVALID_INVOCATION,
575         THIS_TOKEN_OFFSET (MacroStart));
576
577     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
578         "Bad macro invocation: %s \n",
579         Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer);
580     return;
581 }