Fixed compatibility of output.
[AROS.git] / arch / all-pc / acpica / source / compiler / prmacros.c
blobf77d7d9cdbe0f69e785b2b3b254bd9ed9d5d27eb
1 /******************************************************************************
3 * Module Name: prmacros - Preprocessor #define macro support
5 *****************************************************************************/
7 /*
8 * Copyright (C) 2000 - 2013, Intel Corp.
9 * All rights reserved.
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.
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.
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.
44 #include "aslcompiler.h"
45 #include "dtcompiler.h"
48 #define _COMPONENT ASL_PREPROCESSOR
49 ACPI_MODULE_NAME ("prmacros")
52 /*******************************************************************************
54 * FUNCTION: PrDumpPredefinedNames
56 * PARAMETERS: None
58 * RETURN: None
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 ******************************************************************************/
66 void
67 PrDumpPredefinedNames (
68 void)
70 PR_DEFINE_INFO *DefineInfo;
73 DefineInfo = Gbl_DefineList;
74 while (DefineInfo)
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 ******************************************************************************/
99 PR_DEFINE_INFO *
100 PrAddDefine (
101 char *Identifier,
102 char *Replacement,
103 BOOLEAN Persist)
105 char *IdentifierString;
106 char *ReplacementString;
107 PR_DEFINE_INFO *DefineInfo;
110 if (!Replacement)
112 Replacement = "";
115 /* Check for already-defined first */
117 DefineInfo = PrMatchDefine (Identifier);
118 if (DefineInfo)
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
126 * is different.
128 if (strcmp (Replacement, DefineInfo->Replacement))
130 PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME,
131 THIS_TOKEN_OFFSET (Identifier));
133 return (NULL);
136 return (DefineInfo);
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;
154 if (Gbl_DefineList)
156 Gbl_DefineList->Previous = DefineInfo;
159 DefineInfo->Next = Gbl_DefineList;
160 Gbl_DefineList = DefineInfo;
161 return (DefineInfo);
165 /*******************************************************************************
167 * FUNCTION: PrRemoveDefine
169 * PARAMETERS: DefineName - Name of define to be removed
171 * RETURN: None
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 ******************************************************************************/
179 void
180 PrRemoveDefine (
181 char *DefineName)
183 PR_DEFINE_INFO *DefineInfo;
186 /* Match name and delete the node */
188 DefineInfo = Gbl_DefineList;
189 while (DefineInfo)
191 if (!strcmp (DefineName, DefineInfo->Identifier))
193 /* Remove from linked list */
195 if (DefineInfo->Previous)
197 (DefineInfo->Previous)->Next = DefineInfo->Next;
199 else
201 Gbl_DefineList = DefineInfo->Next;
204 if (DefineInfo->Next)
206 (DefineInfo->Next)->Previous = DefineInfo->Previous;
209 free (DefineInfo);
210 return;
213 DefineInfo = DefineInfo->Next;
217 * Name was not found. By definition of #undef, this is not
218 * an error, however.
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 ******************************************************************************/
238 PR_DEFINE_INFO *
239 PrMatchDefine (
240 char *MatchString)
242 PR_DEFINE_INFO *DefineInfo;
245 DefineInfo = Gbl_DefineList;
246 while (DefineInfo)
248 if (!strcmp (MatchString, DefineInfo->Identifier))
250 return (DefineInfo);
253 DefineInfo = DefineInfo->Next;
256 return (NULL);
260 /*******************************************************************************
262 * FUNCTION: PrAddMacro
264 * PARAMETERS: Name - Start of the macro definition
265 * Next - "Next" buffer from GetNextToken
267 * RETURN: None
269 * DESCRIPTION: Add a new macro to the list of #defines. Handles argument
270 * processing.
272 ******************************************************************************/
274 void
275 PrAddMacro (
276 char *Name,
277 char **Next)
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;
294 /* Find the end of the arguments list */
296 TokenOffset = Name - Gbl_MainTokenBuffer + strlen (Name) + 1;
297 while (1)
299 BufferChar = Gbl_CurrentLineBuffer[TokenOffset];
300 if (BufferChar == '(')
302 Depth++;
304 else if (BufferChar == ')')
306 Depth--;
308 else if (BufferChar == 0)
310 PrError (ASL_ERROR, ASL_MSG_MACRO_SYNTAX, TokenOffset);
311 return;
314 if (Depth == 0)
316 /* Found arg list end */
318 EndOfArgList = TokenOffset;
319 break;
322 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);
334 if (!Token)
336 /* This is the case for a NULL macro body */
338 BodyInSource = "";
339 goto AddMacroToList;
342 /* Don't go beyond the argument list */
344 TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
345 if (TokenOffset > EndOfArgList)
347 break;
350 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
351 "Macro arg: %s \n",
352 Gbl_CurrentLineNumber, Token);
354 Args[i].Name = UtLocalCalloc (strlen (Token) + 1);
355 strcpy (Args[i].Name, Token);
357 Args[i].UseCount = 0;
359 ArgCount++;
360 if (ArgCount >= PR_MAX_MACRO_ARGS)
362 PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS, TokenOffset);
363 return;
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);
374 while (Token)
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]);
397 Args[i].UseCount++;
398 if (Args[i].UseCount >= PR_MAX_ARG_INSTANCES)
400 PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS,
401 THIS_TOKEN_OFFSET (Token));
403 return;
405 break;
409 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
412 BodyInSource = &Gbl_CurrentLineBuffer[MacroBodyOffset];
415 AddMacroToList:
417 /* Check if name is already defined first */
419 DefineInfo = PrMatchDefine (Name);
420 if (DefineInfo)
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));
435 return;
438 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
439 "Macro body: %s \n",
440 Gbl_CurrentLineNumber, BodyInSource);
442 /* Add macro to the #define list */
444 DefineInfo = PrAddDefine (Name, BodyInSource, FALSE);
445 if (DefineInfo)
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
463 * the token buffer
464 * DefineInfo - Info for this macro
465 * Next - "Next" buffer from GetNextToken
467 * RETURN: None
469 * DESCRIPTION: Expand a macro invocation
471 ******************************************************************************/
473 void
474 PrDoMacroInvocation (
475 char *TokenBuffer,
476 char *MacroStart,
477 PR_DEFINE_INFO *DefineInfo,
478 char **Next)
480 PR_MACRO_ARG *Args;
481 char *Token = NULL;
482 UINT32 TokenOffset;
483 UINT32 Length;
484 UINT32 i;
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;
494 if (!Args->Name)
496 /* This macro has no arguments */
498 Token = PrGetNextToken (NULL, PR_MACRO_ARGUMENTS, Next);
499 if (!Token)
501 goto BadInvocation;
504 TokenOffset = (MacroStart - TokenBuffer);
505 Length = Token - MacroStart + strlen (Token) + 1;
507 PrReplaceData (
508 &Gbl_CurrentLineBuffer[TokenOffset], Length,
509 Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
510 return;
513 while (Args->Name)
515 /* Get the next argument from macro invocation */
517 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
518 if (!Token)
520 goto BadInvocation;
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)
532 break;
535 PrReplaceData (
536 &Gbl_MacroTokenBuffer[Args->Offset[i]], strlen (Args->Name),
537 Token, strlen (Token));
539 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
540 "ExpandArg: %s \n",
541 Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer);
544 Args++;
547 /* TBD: need to make sure macro was not invoked with too many arguments */
549 if (!Token)
551 return;
554 /* Replace the entire macro invocation with the expanded macro */
556 TokenOffset = (MacroStart - TokenBuffer);
557 Length = Token - MacroStart + strlen (Token) + 1;
559 PrReplaceData (
560 &Gbl_CurrentLineBuffer[TokenOffset], Length,
561 Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
563 return;
566 BadInvocation:
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);
573 return;