1 /******************************************************************************
3 * Module Name: prmacros - Preprocessor #define macro support
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
44 #include "aslcompiler.h"
45 #include "dtcompiler.h"
48 #define _COMPONENT ASL_PREPROCESSOR
49 ACPI_MODULE_NAME ("prmacros")
52 /*******************************************************************************
54 * FUNCTION: PrDumpPredefinedNames
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.
64 ******************************************************************************/
67 PrDumpPredefinedNames (
70 PR_DEFINE_INFO
*DefineInfo
;
73 DefineInfo
= Gbl_DefineList
;
76 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
77 "Predefined #define: %s->%s\n",
78 0, DefineInfo
->Identifier
, DefineInfo
->Replacement
);
80 DefineInfo
= DefineInfo
->Next
;
85 /*******************************************************************************
87 * FUNCTION: PrAddDefine
89 * PARAMETERS: Identifier - Name to be replaced
90 * Replacement - Replacement for Identifier
91 * Persist - Keep define across multiple compiles?
93 * RETURN: A new define_info struct. NULL on error.
95 * DESCRIPTION: Add a new #define to the global list
97 ******************************************************************************/
105 char *IdentifierString
;
106 char *ReplacementString
;
107 PR_DEFINE_INFO
*DefineInfo
;
115 /* Check for already-defined first */
117 DefineInfo
= PrMatchDefine (Identifier
);
120 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
,
121 "#define: name already exists: %s\n",
122 Gbl_CurrentLineNumber
, Identifier
);
125 * Name already exists. This is only an error if the target name
128 if (strcmp (Replacement
, DefineInfo
->Replacement
))
130 PrError (ASL_ERROR
, ASL_MSG_EXISTING_NAME
,
131 THIS_TOKEN_OFFSET (Identifier
));
139 /* Copy input strings */
141 IdentifierString
= UtLocalCalloc (strlen (Identifier
) + 1);
142 strcpy (IdentifierString
, Identifier
);
144 ReplacementString
= UtLocalCalloc (strlen (Replacement
) + 1);
145 strcpy (ReplacementString
, Replacement
);
147 /* Init and link new define info struct */
149 DefineInfo
= UtLocalCalloc (sizeof (PR_DEFINE_INFO
));
150 DefineInfo
->Replacement
= ReplacementString
;
151 DefineInfo
->Identifier
= IdentifierString
;
152 DefineInfo
->Persist
= Persist
;
156 Gbl_DefineList
->Previous
= DefineInfo
;
159 DefineInfo
->Next
= Gbl_DefineList
;
160 Gbl_DefineList
= DefineInfo
;
165 /*******************************************************************************
167 * FUNCTION: PrRemoveDefine
169 * PARAMETERS: DefineName - Name of define to be removed
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.
177 ******************************************************************************/
183 PR_DEFINE_INFO
*DefineInfo
;
186 /* Match name and delete the node */
188 DefineInfo
= Gbl_DefineList
;
191 if (!strcmp (DefineName
, DefineInfo
->Identifier
))
193 /* Remove from linked list */
195 if (DefineInfo
->Previous
)
197 (DefineInfo
->Previous
)->Next
= DefineInfo
->Next
;
201 Gbl_DefineList
= DefineInfo
->Next
;
204 if (DefineInfo
->Next
)
206 (DefineInfo
->Next
)->Previous
= DefineInfo
->Previous
;
213 DefineInfo
= DefineInfo
->Next
;
217 * Name was not found. By definition of #undef, this is not
220 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
221 "#undef: could not find %s\n",
222 Gbl_CurrentLineNumber
, DefineName
);
226 /*******************************************************************************
228 * FUNCTION: PrMatchDefine
230 * PARAMETERS: MatchString - Name associated with the #define
232 * RETURN: Matched string if found. NULL otherwise.
234 * DESCRIPTION: Find a name in global #define list
236 ******************************************************************************/
242 PR_DEFINE_INFO
*DefineInfo
;
245 DefineInfo
= Gbl_DefineList
;
248 if (!strcmp (MatchString
, DefineInfo
->Identifier
))
253 DefineInfo
= DefineInfo
->Next
;
260 /*******************************************************************************
262 * FUNCTION: PrAddMacro
264 * PARAMETERS: Name - Start of the macro definition
265 * Next - "Next" buffer from GetNextToken
269 * DESCRIPTION: Add a new macro to the list of #defines. Handles argument
272 ******************************************************************************/
280 ACPI_SIZE TokenOffset
;
281 ACPI_SIZE MacroBodyOffset
;
282 PR_DEFINE_INFO
*DefineInfo
;
294 /* Find the end of the arguments list */
296 TokenOffset
= Name
- Gbl_MainTokenBuffer
+ strlen (Name
) + 1;
299 BufferChar
= Gbl_CurrentLineBuffer
[TokenOffset
];
300 if (BufferChar
== '(')
304 else if (BufferChar
== ')')
308 else if (BufferChar
== 0)
310 PrError (ASL_ERROR
, ASL_MSG_MACRO_SYNTAX
, TokenOffset
);
316 /* Found arg list end */
318 EndOfArgList
= TokenOffset
;
325 /* At this point, we know that we have a reasonable argument list */
327 Args
= UtLocalCalloc (sizeof (PR_MACRO_ARG
) * PR_MAX_MACRO_ARGS
);
329 /* Get the macro argument names */
331 for (i
= 0; i
< PR_MAX_MACRO_ARGS
; i
++)
333 Token
= PrGetNextToken (NULL
, PR_MACRO_SEPARATORS
, Next
);
336 /* This is the case for a NULL macro body */
342 /* Don't go beyond the argument list */
344 TokenOffset
= Token
- Gbl_MainTokenBuffer
+ strlen (Token
);
345 if (TokenOffset
> EndOfArgList
)
350 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
352 Gbl_CurrentLineNumber
, Token
);
354 Args
[i
].Name
= UtLocalCalloc (strlen (Token
) + 1);
355 strcpy (Args
[i
].Name
, Token
);
357 Args
[i
].UseCount
= 0;
360 if (ArgCount
>= PR_MAX_MACRO_ARGS
)
362 PrError (ASL_ERROR
, ASL_MSG_TOO_MANY_ARGUMENTS
, TokenOffset
);
367 /* Get the macro body. Token now points to start of body */
369 MacroBodyOffset
= Token
- Gbl_MainTokenBuffer
;
371 /* Match each method arg in the macro body for later use */
373 Token
= PrGetNextToken (NULL
, PR_MACRO_SEPARATORS
, Next
);
376 /* Search the macro arg list for matching arg */
378 for (i
= 0; Args
[i
].Name
&& (i
< PR_MAX_MACRO_ARGS
); i
++)
381 * Save argument offset within macro body. This is the mechanism
382 * used to expand the macro upon invocation.
384 * Handles multiple instances of the same argument
386 if (!strcmp (Token
, Args
[i
].Name
))
388 UseCount
= Args
[i
].UseCount
;
390 Args
[i
].Offset
[UseCount
] = (Token
- Gbl_MainTokenBuffer
) - MacroBodyOffset
;
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
]);
398 if (Args
[i
].UseCount
>= PR_MAX_ARG_INSTANCES
)
400 PrError (ASL_ERROR
, ASL_MSG_TOO_MANY_ARGUMENTS
,
401 THIS_TOKEN_OFFSET (Token
));
409 Token
= PrGetNextToken (NULL
, PR_MACRO_SEPARATORS
, Next
);
412 BodyInSource
= &Gbl_CurrentLineBuffer
[MacroBodyOffset
];
417 /* Check if name is already defined first */
419 DefineInfo
= PrMatchDefine (Name
);
422 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
423 "#define: macro name already exists: %s\n",
424 Gbl_CurrentLineNumber
, Name
);
426 /* Error only if not exactly the same macro */
428 if (strcmp (DefineInfo
->Body
, BodyInSource
) ||
429 (DefineInfo
->ArgCount
!= ArgCount
))
431 PrError (ASL_ERROR
, ASL_MSG_EXISTING_NAME
,
432 THIS_TOKEN_OFFSET (Name
));
438 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
440 Gbl_CurrentLineNumber
, BodyInSource
);
442 /* Add macro to the #define list */
444 DefineInfo
= PrAddDefine (Name
, BodyInSource
, FALSE
);
447 Body
= UtLocalCalloc (strlen (BodyInSource
) + 1);
448 strcpy (Body
, BodyInSource
);
450 DefineInfo
->Body
= Body
;
451 DefineInfo
->Args
= Args
;
452 DefineInfo
->ArgCount
= ArgCount
;
457 /*******************************************************************************
459 * FUNCTION: PrDoMacroInvocation
461 * PARAMETERS: TokenBuffer - Current line buffer
462 * MacroStart - Start of the macro invocation within
464 * DefineInfo - Info for this macro
465 * Next - "Next" buffer from GetNextToken
469 * DESCRIPTION: Expand a macro invocation
471 ******************************************************************************/
474 PrDoMacroInvocation (
477 PR_DEFINE_INFO
*DefineInfo
,
487 /* Take a copy of the macro body for expansion */
489 strcpy (Gbl_MacroTokenBuffer
, DefineInfo
->Body
);
491 /* Replace each argument within the prototype body */
493 Args
= DefineInfo
->Args
;
496 /* This macro has no arguments */
498 Token
= PrGetNextToken (NULL
, PR_MACRO_ARGUMENTS
, Next
);
504 TokenOffset
= (MacroStart
- TokenBuffer
);
505 Length
= Token
- MacroStart
+ strlen (Token
) + 1;
508 &Gbl_CurrentLineBuffer
[TokenOffset
], Length
,
509 Gbl_MacroTokenBuffer
, strlen (Gbl_MacroTokenBuffer
));
515 /* Get the next argument from macro invocation */
517 Token
= PrGetNextToken (NULL
, PR_MACRO_SEPARATORS
, Next
);
523 /* Replace all instances of this argument */
525 for (i
= 0; i
< Args
->UseCount
; i
++)
527 /* Offset zero indicates "arg not used" */
528 /* TBD: Not really needed now, with UseCount available */
530 if (Args
->Offset
[i
] == 0)
536 &Gbl_MacroTokenBuffer
[Args
->Offset
[i
]], strlen (Args
->Name
),
537 Token
, strlen (Token
));
539 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
541 Gbl_CurrentLineNumber
, Gbl_MacroTokenBuffer
);
547 /* TBD: need to make sure macro was not invoked with too many arguments */
554 /* Replace the entire macro invocation with the expanded macro */
556 TokenOffset
= (MacroStart
- TokenBuffer
);
557 Length
= Token
- MacroStart
+ strlen (Token
) + 1;
560 &Gbl_CurrentLineBuffer
[TokenOffset
], Length
,
561 Gbl_MacroTokenBuffer
, strlen (Gbl_MacroTokenBuffer
));
567 PrError (ASL_ERROR
, ASL_MSG_INVALID_INVOCATION
,
568 THIS_TOKEN_OFFSET (MacroStart
));
570 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
571 "Bad macro invocation: %s \n",
572 Gbl_CurrentLineNumber
, Gbl_MacroTokenBuffer
);