prmacros.c revision 1.1.1.16 1 /******************************************************************************
2 *
3 * Module Name: prmacros - Preprocessor #define macro support
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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
46 #define _COMPONENT ASL_PREPROCESSOR
47 ACPI_MODULE_NAME ("prmacros")
48
49
50 /*******************************************************************************
51 *
52 * FUNCTION: PrDumpPredefinedNames
53 *
54 * PARAMETERS: None
55 *
56 * RETURN: None
57 *
58 * DESCRIPTION: Dump the list of #defines. Used as the preprocessor starts, to
59 * display the names that were defined on the command line.
60 * Debug information only.
61 *
62 ******************************************************************************/
63
64 void
65 PrDumpPredefinedNames (
66 void)
67 {
68 PR_DEFINE_INFO *DefineInfo;
69
70
71 DefineInfo = AslGbl_DefineList;
72 while (DefineInfo)
73 {
74 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
75 "Predefined #define: %s->%s\n",
76 0, DefineInfo->Identifier, DefineInfo->Replacement);
77
78 DefineInfo = DefineInfo->Next;
79 }
80 }
81
82
83 /*******************************************************************************
84 *
85 * FUNCTION: PrAddDefine
86 *
87 * PARAMETERS: Identifier - Name to be replaced
88 * Replacement - Replacement for Identifier
89 * Persist - Keep define across multiple compiles?
90 *
91 * RETURN: A new define_info struct. NULL on error.
92 *
93 * DESCRIPTION: Add a new #define to the global list
94 *
95 ******************************************************************************/
96
97 PR_DEFINE_INFO *
98 PrAddDefine (
99 char *Identifier,
100 char *Replacement,
101 BOOLEAN Persist)
102 {
103 char *IdentifierString;
104 char *ReplacementString;
105 PR_DEFINE_INFO *DefineInfo;
106
107
108 if (!Replacement)
109 {
110 Replacement = "";
111 }
112
113 /* Check for already-defined first */
114
115 DefineInfo = PrMatchDefine (Identifier);
116 if (DefineInfo)
117 {
118 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
119 "#define: name already exists: %s\n",
120 AslGbl_CurrentLineNumber, Identifier);
121
122 /*
123 * Name already exists. This is only an error if the target name
124 * is different.
125 */
126 if (strcmp (Replacement, DefineInfo->Replacement))
127 {
128 PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME,
129 THIS_TOKEN_OFFSET (Identifier));
130
131 return (NULL);
132 }
133
134 return (DefineInfo);
135 }
136
137 /* Copy input strings */
138
139 IdentifierString = UtLocalCalloc (strlen (Identifier) + 1);
140 strcpy (IdentifierString, Identifier);
141
142 ReplacementString = UtLocalCalloc (strlen (Replacement) + 1);
143 strcpy (ReplacementString, Replacement);
144
145 /* Init and link new define info struct */
146
147 DefineInfo = UtLocalCalloc (sizeof (PR_DEFINE_INFO));
148 DefineInfo->Replacement = ReplacementString;
149 DefineInfo->Identifier = IdentifierString;
150 DefineInfo->Persist = Persist;
151
152 if (AslGbl_DefineList)
153 {
154 AslGbl_DefineList->Previous = DefineInfo;
155 }
156
157 DefineInfo->Next = AslGbl_DefineList;
158 AslGbl_DefineList = DefineInfo;
159 return (DefineInfo);
160 }
161
162
163 /*******************************************************************************
164 *
165 * FUNCTION: PrRemoveDefine
166 *
167 * PARAMETERS: DefineName - Name of define to be removed
168 *
169 * RETURN: None
170 *
171 * DESCRIPTION: Implements #undef. Remove a #define if found in the global
172 * list. No error if the target of the #undef does not exist,
173 * as per the C #undef definition.
174 *
175 ******************************************************************************/
176
177 void
178 PrRemoveDefine (
179 char *DefineName)
180 {
181 PR_DEFINE_INFO *DefineInfo;
182
183
184 /* Match name and delete the node */
185
186 DefineInfo = AslGbl_DefineList;
187 while (DefineInfo)
188 {
189 if (!strcmp (DefineName, DefineInfo->Identifier))
190 {
191 /* Remove from linked list */
192
193 if (DefineInfo->Previous)
194 {
195 (DefineInfo->Previous)->Next = DefineInfo->Next;
196 }
197 else
198 {
199 AslGbl_DefineList = DefineInfo->Next;
200 }
201
202 if (DefineInfo->Next)
203 {
204 (DefineInfo->Next)->Previous = DefineInfo->Previous;
205 }
206
207 free (DefineInfo);
208 return;
209 }
210
211 DefineInfo = DefineInfo->Next;
212 }
213
214 /*
215 * Name was not found. By definition of #undef, this is not
216 * an error, however.
217 */
218 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
219 "#undef: could not find %s\n",
220 AslGbl_CurrentLineNumber, DefineName);
221 }
222
223
224 /*******************************************************************************
225 *
226 * FUNCTION: PrMatchDefine
227 *
228 * PARAMETERS: MatchString - Name associated with the #define
229 *
230 * RETURN: Matched string if found. NULL otherwise.
231 *
232 * DESCRIPTION: Find a name in global #define list
233 *
234 ******************************************************************************/
235
236 PR_DEFINE_INFO *
237 PrMatchDefine (
238 char *MatchString)
239 {
240 PR_DEFINE_INFO *DefineInfo;
241
242
243 DefineInfo = AslGbl_DefineList;
244 while (DefineInfo)
245 {
246 if (!strcmp (MatchString, DefineInfo->Identifier))
247 {
248 return (DefineInfo);
249 }
250
251 DefineInfo = DefineInfo->Next;
252 }
253
254 return (NULL);
255 }
256
257
258 /*******************************************************************************
259 *
260 * FUNCTION: PrAddMacro
261 *
262 * PARAMETERS: Name - Start of the macro definition
263 * Next - "Next" buffer from GetNextToken
264 *
265 * RETURN: None
266 *
267 * DESCRIPTION: Add a new macro to the list of #defines. Handles argument
268 * processing.
269 *
270 ******************************************************************************/
271
272 void
273 PrAddMacro (
274 char *Name,
275 char **Next)
276 {
277 char *Token = NULL;
278 ACPI_SIZE TokenOffset;
279 ACPI_SIZE MacroBodyOffset;
280 PR_DEFINE_INFO *DefineInfo;
281 PR_MACRO_ARG *Args;
282 char *Body;
283 char *BodyInSource;
284 UINT32 i;
285 UINT16 UseCount = 0;
286 UINT16 ArgCount = 0;
287 UINT32 Depth = 1;
288 /*UINT32 Depth = 1;*/
289 UINT32 EndOfArgList;
290 char BufferChar;
291
292 /* Find the end of the arguments list */
293
294 TokenOffset = Name - AslGbl_MainTokenBuffer + strlen (Name) + 1;
295 while (1)
296 {
297 BufferChar = AslGbl_CurrentLineBuffer[TokenOffset];
298 if (BufferChar == '(')
299 {
300 Depth++;
301 }
302 else if (BufferChar == ')')
303 {
304 Depth--;
305 }
306 else if (BufferChar == 0)
307 {
308 PrError (ASL_ERROR, ASL_MSG_MACRO_SYNTAX, TokenOffset);
309 return;
310 }
311
312 if (Depth == 0)
313 {
314 /* Found arg list end */
315
316 EndOfArgList = TokenOffset;
317 break;
318 }
319
320 TokenOffset++;
321 }
322
323 /* At this point, we know that we have a reasonable argument list */
324
325 Args = UtLocalCalloc (sizeof (PR_MACRO_ARG) * PR_MAX_MACRO_ARGS);
326
327 /* Get the macro argument names */
328
329 for (i = 0; i < PR_MAX_MACRO_ARGS; i++)
330 {
331 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
332
333 if (!Token)
334 {
335 /* This is the case for a NULL macro body */
336
337 BodyInSource = "";
338 goto AddMacroToList;
339 }
340
341 /* Don't go beyond the argument list */
342
343 TokenOffset = Token - AslGbl_MainTokenBuffer + strlen (Token);
344 if (TokenOffset > EndOfArgList)
345 {
346 break;
347 }
348
349 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
350 "Macro param: %s\n",
351 AslGbl_CurrentLineNumber, Token);
352
353 Args[i].Name = UtLocalCalloc (strlen (Token) + 1);
354 strcpy (Args[i].Name, Token);
355
356 Args[i].UseCount = 0;
357 ArgCount++;
358 if (ArgCount >= PR_MAX_MACRO_ARGS)
359 {
360 PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS, TokenOffset);
361 goto ErrorExit;
362 }
363 }
364
365 /* Get the macro body. Token now points to start of body */
366
367 MacroBodyOffset = Token - AslGbl_MainTokenBuffer;
368
369 /* Match each method arg in the macro body for later use */
370
371 while (Token)
372 {
373 /* Search the macro arg list for matching arg */
374
375 for (i = 0; ((i < PR_MAX_MACRO_ARGS) && Args[i].Name); i++)
376 {
377 /*
378 * Save argument offset within macro body. This is the mechanism
379 * used to expand the macro upon invocation.
380 *
381 * Handles multiple instances of the same argument
382 */
383 if (!strcmp (Token, Args[i].Name))
384 {
385 UseCount = Args[i].UseCount;
386
387 Args[i].Offset[UseCount] =
388 (Token - AslGbl_MainTokenBuffer) - MacroBodyOffset;
389
390
391 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
392 "Macro Arg #%u: %s UseCount %u Offset %u\n",
393 AslGbl_CurrentLineNumber, i, Token,
394 UseCount+1, Args[i].Offset[UseCount]);
395
396 Args[i].UseCount++;
397
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 = &AslGbl_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 AslGbl_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 AslGbl_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 UINT32 Diff1;
493 UINT32 Diff2;
494
495 /* Take a copy of the macro body for expansion */
496
497 strcpy (AslGbl_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
508 if (!Token)
509 {
510 goto BadInvocation;
511 }
512
513 TokenOffset = (MacroStart - TokenBuffer);
514 Length = Token - MacroStart + strlen (Token) + 1;
515
516 PrReplaceData (
517 &AslGbl_CurrentLineBuffer[TokenOffset], Length,
518 AslGbl_MacroTokenBuffer, strlen (AslGbl_MacroTokenBuffer));
519 return;
520 }
521
522 while (Args->Name)
523 {
524 /* Get the next argument from macro invocation */
525
526 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
527 if (!Token)
528 {
529 goto BadInvocation;
530 }
531
532 /*
533 * Avoid optimizing using just 1 signed int due to specific
534 * non-portable implementations of signed ints
535 */
536 Diff1 = strlen (Args->Name) > strlen (Token) ? strlen (Args->Name) -
537 strlen (Token) : 0;
538
539 Diff2 = strlen (Args->Name) < strlen (Token) ? strlen (Token) -
540 strlen (Args->Name) : 0;
541
542 /* Replace all instances of this argument */
543
544 for (i = 0; i < Args->UseCount; i++)
545 {
546 /*
547 * To test the output of the preprocessed macro function that
548 * is passed to the compiler
549 */
550
551 /*
552 * fprintf (stderr, "Current token = %s \t Current arg_name = %s \
553 * \t strlen (Token) = %u \t strlen (Args->Name) = %u \t Offset = %u \
554 * \t UseCount = %u \t", Token, Args->Name, strlen (Token), \
555 * strlen (Args->Name), Args->Offset[i], Args->UseCount);
556 */
557
558 AslGbl_MacroTokenReplaceBuffer = (char *) calloc ((strlen (AslGbl_MacroTokenBuffer)), sizeof (char));
559
560 PrReplaceResizeSubstring (Args, Diff1, Diff2, i, Token);
561
562 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
563 "ExpandArg: %s\n",
564 AslGbl_CurrentLineNumber, AslGbl_MacroTokenBuffer);
565 }
566
567 Args++;
568 }
569
570 if (!Token)
571 {
572 return;
573 }
574
575 /* Replace the entire macro invocation with the expanded macro */
576
577 TokenOffset = (MacroStart - TokenBuffer);
578 Length = Token - MacroStart + strlen (Token) + 1;
579
580 PrReplaceData (
581 &AslGbl_CurrentLineBuffer[TokenOffset], Length,
582 AslGbl_MacroTokenBuffer, strlen (AslGbl_MacroTokenBuffer));
583
584 return;
585
586 BadInvocation:
587 PrError (ASL_ERROR, ASL_MSG_INVALID_INVOCATION,
588 THIS_TOKEN_OFFSET (MacroStart));
589
590 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
591 "Bad macro invocation: %s\n",
592 AslGbl_CurrentLineNumber, AslGbl_MacroTokenBuffer);
593 return;
594 }
595