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