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