prmacros.c revision 1.1.1.11 1 /******************************************************************************
2 *
3 * Module Name: prmacros - Preprocessor #define macro support
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2019, 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
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 EndOfArgList;
289 char BufferChar;
290
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 if (!Token)
333 {
334 /* This is the case for a NULL macro body */
335
336 BodyInSource = "";
337 goto AddMacroToList;
338 }
339
340 /* Don't go beyond the argument list */
341
342 TokenOffset = Token - AslGbl_MainTokenBuffer + strlen (Token);
343 if (TokenOffset > EndOfArgList)
344 {
345 break;
346 }
347
348 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
349 "Macro arg: %s \n",
350 AslGbl_CurrentLineNumber, Token);
351
352 Args[i].Name = UtLocalCalloc (strlen (Token) + 1);
353 strcpy (Args[i].Name, Token);
354
355 Args[i].UseCount = 0;
356
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 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
372 while (Token)
373 {
374 /* Search the macro arg list for matching arg */
375
376 for (i = 0; ((i < PR_MAX_MACRO_ARGS) && Args[i].Name); i++)
377 {
378 /*
379 * Save argument offset within macro body. This is the mechanism
380 * used to expand the macro upon invocation.
381 *
382 * Handles multiple instances of the same argument
383 */
384 if (!strcmp (Token, Args[i].Name))
385 {
386 UseCount = Args[i].UseCount;
387
388 Args[i].Offset[UseCount] =
389 (Token - AslGbl_MainTokenBuffer) - MacroBodyOffset;
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 if (Args[i].UseCount >= PR_MAX_ARG_INSTANCES)
398 {
399 PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS,
400 THIS_TOKEN_OFFSET (Token));
401
402 goto ErrorExit;
403 }
404 break;
405 }
406 }
407
408 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
409 }
410
411 BodyInSource = &AslGbl_CurrentLineBuffer[MacroBodyOffset];
412
413
414 AddMacroToList:
415
416 /* Check if name is already defined first */
417
418 DefineInfo = PrMatchDefine (Name);
419 if (DefineInfo)
420 {
421 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
422 "#define: macro name already exists: %s\n",
423 AslGbl_CurrentLineNumber, Name);
424
425 /* Error only if not exactly the same macro */
426
427 if (strcmp (DefineInfo->Body, BodyInSource) ||
428 (DefineInfo->ArgCount != ArgCount))
429 {
430 PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME,
431 THIS_TOKEN_OFFSET (Name));
432 }
433
434 goto ErrorExit;
435 }
436
437 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
438 "Macro body: %s \n",
439 AslGbl_CurrentLineNumber, BodyInSource);
440
441 /* Add macro to the #define list */
442
443 DefineInfo = PrAddDefine (Name, BodyInSource, FALSE);
444 if (DefineInfo)
445 {
446 Body = UtLocalCalloc (strlen (BodyInSource) + 1);
447 strcpy (Body, BodyInSource);
448
449 DefineInfo->Body = Body;
450 DefineInfo->Args = Args;
451 DefineInfo->ArgCount = ArgCount;
452 }
453
454 return;
455
456
457 ErrorExit:
458 ACPI_FREE (Args);
459 return;
460 }
461
462
463 /*******************************************************************************
464 *
465 * FUNCTION: PrDoMacroInvocation
466 *
467 * PARAMETERS: TokenBuffer - Current line buffer
468 * MacroStart - Start of the macro invocation within
469 * the token buffer
470 * DefineInfo - Info for this macro
471 * Next - "Next" buffer from GetNextToken
472 *
473 * RETURN: None
474 *
475 * DESCRIPTION: Expand a macro invocation
476 *
477 ******************************************************************************/
478
479 void
480 PrDoMacroInvocation (
481 char *TokenBuffer,
482 char *MacroStart,
483 PR_DEFINE_INFO *DefineInfo,
484 char **Next)
485 {
486 PR_MACRO_ARG *Args;
487 char *Token = NULL;
488 UINT32 TokenOffset;
489 UINT32 Length;
490 UINT32 i;
491
492
493 /* Take a copy of the macro body for expansion */
494
495 strcpy (AslGbl_MacroTokenBuffer, DefineInfo->Body);
496
497 /* Replace each argument within the prototype body */
498
499 Args = DefineInfo->Args;
500 if (!Args->Name)
501 {
502 /* This macro has no arguments */
503
504 Token = PrGetNextToken (NULL, PR_MACRO_ARGUMENTS, Next);
505 if (!Token)
506 {
507 goto BadInvocation;
508 }
509
510 TokenOffset = (MacroStart - TokenBuffer);
511 Length = Token - MacroStart + strlen (Token) + 1;
512
513 PrReplaceData (
514 &AslGbl_CurrentLineBuffer[TokenOffset], Length,
515 AslGbl_MacroTokenBuffer, strlen (AslGbl_MacroTokenBuffer));
516 return;
517 }
518
519 while (Args->Name)
520 {
521 /* Get the next argument from macro invocation */
522
523 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
524 if (!Token)
525 {
526 goto BadInvocation;
527 }
528
529 /* Replace all instances of this argument */
530
531 for (i = 0; i < Args->UseCount; i++)
532 {
533 /* Offset zero indicates "arg not used" */
534 /* TBD: Not really needed now, with UseCount available */
535
536 if (Args->Offset[i] == 0)
537 {
538 break;
539 }
540
541 PrReplaceData (
542 &AslGbl_MacroTokenBuffer[Args->Offset[i]], strlen (Args->Name),
543 Token, strlen (Token));
544
545 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
546 "ExpandArg: %s \n",
547 AslGbl_CurrentLineNumber, AslGbl_MacroTokenBuffer);
548 }
549
550 Args++;
551 }
552
553 /* TBD: need to make sure macro was not invoked with too many arguments */
554
555 if (!Token)
556 {
557 return;
558 }
559
560 /* Replace the entire macro invocation with the expanded macro */
561
562 TokenOffset = (MacroStart - TokenBuffer);
563 Length = Token - MacroStart + strlen (Token) + 1;
564
565 PrReplaceData (
566 &AslGbl_CurrentLineBuffer[TokenOffset], Length,
567 AslGbl_MacroTokenBuffer, strlen (AslGbl_MacroTokenBuffer));
568
569 return;
570
571
572 BadInvocation:
573 PrError (ASL_ERROR, ASL_MSG_INVALID_INVOCATION,
574 THIS_TOKEN_OFFSET (MacroStart));
575
576 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
577 "Bad macro invocation: %s \n",
578 AslGbl_CurrentLineNumber, AslGbl_MacroTokenBuffer);
579 return;
580 }
581