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 <contrib/dev/acpica/compiler/aslcompiler.h> 45 #include <contrib/dev/acpica/compiler/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