prmacros.c revision 1.1.1.1 1 /******************************************************************************
2 *
3 * Module Name: prmacros - Preprocessor #define macro support
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2013, 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 return;
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] = (Token - Gbl_MainTokenBuffer) - MacroBodyOffset;
391
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]);
396
397 Args[i].UseCount++;
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 return;
404 }
405 break;
406 }
407 }
408
409 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
410 }
411
412 BodyInSource = &Gbl_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 Gbl_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 return;
436 }
437
438 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
439 "Macro body: %s \n",
440 Gbl_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
456
457 /*******************************************************************************
458 *
459 * FUNCTION: PrDoMacroInvocation
460 *
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
466 *
467 * RETURN: None
468 *
469 * DESCRIPTION: Expand a macro invocation
470 *
471 ******************************************************************************/
472
473 void
474 PrDoMacroInvocation (
475 char *TokenBuffer,
476 char *MacroStart,
477 PR_DEFINE_INFO *DefineInfo,
478 char **Next)
479 {
480 PR_MACRO_ARG *Args;
481 char *Token = NULL;
482 UINT32 TokenOffset;
483 UINT32 Length;
484 UINT32 i;
485
486
487 /* Take a copy of the macro body for expansion */
488
489 strcpy (Gbl_MacroTokenBuffer, DefineInfo->Body);
490
491 /* Replace each argument within the prototype body */
492
493 Args = DefineInfo->Args;
494 if (!Args->Name)
495 {
496 /* This macro has no arguments */
497
498 Token = PrGetNextToken (NULL, PR_MACRO_ARGUMENTS, Next);
499 if (!Token)
500 {
501 goto BadInvocation;
502 }
503
504 TokenOffset = (MacroStart - TokenBuffer);
505 Length = Token - MacroStart + strlen (Token) + 1;
506
507 PrReplaceData (
508 &Gbl_CurrentLineBuffer[TokenOffset], Length,
509 Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
510 return;
511 }
512
513 while (Args->Name)
514 {
515 /* Get the next argument from macro invocation */
516
517 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next);
518 if (!Token)
519 {
520 goto BadInvocation;
521 }
522
523 /* Replace all instances of this argument */
524
525 for (i = 0; i < Args->UseCount; i++)
526 {
527 /* Offset zero indicates "arg not used" */
528 /* TBD: Not really needed now, with UseCount available */
529
530 if (Args->Offset[i] == 0)
531 {
532 break;
533 }
534
535 PrReplaceData (
536 &Gbl_MacroTokenBuffer[Args->Offset[i]], strlen (Args->Name),
537 Token, strlen (Token));
538
539 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
540 "ExpandArg: %s \n",
541 Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer);
542 }
543
544 Args++;
545 }
546
547 /* TBD: need to make sure macro was not invoked with too many arguments */
548
549 if (!Token)
550 {
551 return;
552 }
553
554 /* Replace the entire macro invocation with the expanded macro */
555
556 TokenOffset = (MacroStart - TokenBuffer);
557 Length = Token - MacroStart + strlen (Token) + 1;
558
559 PrReplaceData (
560 &Gbl_CurrentLineBuffer[TokenOffset], Length,
561 Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer));
562
563 return;
564
565
566 BadInvocation:
567 PrError (ASL_ERROR, ASL_MSG_INVALID_INVOCATION,
568 THIS_TOKEN_OFFSET (MacroStart));
569
570 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
571 "Bad macro invocation: %s \n",
572 Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer);
573 return;
574 }
575