1 /****************************************************************************** 2 * 3 * Module Name: prmacros - Preprocessor #define macro support 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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 }