1 /****************************************************************************** 2 * 3 * Module Name: asltree - parse tree management 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, 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 "aslcompiler.y.h" 46 #include "acapps.h" 47 #include "acconvert.h" 48 #include <time.h> 49 50 #define _COMPONENT ACPI_COMPILER 51 ACPI_MODULE_NAME ("asltree") 52 53 /* Local prototypes */ 54 55 static ACPI_PARSE_OBJECT * 56 TrGetNextNode ( 57 void); 58 59 60 /******************************************************************************* 61 * 62 * FUNCTION: TrSetParent 63 * 64 * PARAMETERS: Op - To be set to new parent 65 * ParentOp - The parent 66 * 67 * RETURN: None, sets Op parent directly 68 * 69 * DESCRIPTION: Change the parent of a parse op. 70 * 71 ******************************************************************************/ 72 73 void 74 TrSetParent ( 75 ACPI_PARSE_OBJECT *Op, 76 ACPI_PARSE_OBJECT *ParentOp) 77 { 78 79 Op->Asl.Parent = ParentOp; 80 } 81 82 83 /******************************************************************************* 84 * 85 * FUNCTION: TrGetNextNode 86 * 87 * PARAMETERS: None 88 * 89 * RETURN: New parse node. Aborts on allocation failure 90 * 91 * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local 92 * dynamic memory manager for performance reasons (This has a 93 * major impact on the speed of the compiler.) 94 * 95 ******************************************************************************/ 96 97 static ACPI_PARSE_OBJECT * 98 TrGetNextNode ( 99 void) 100 { 101 ASL_CACHE_INFO *Cache; 102 103 104 if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast) 105 { 106 /* Allocate a new buffer */ 107 108 Cache = UtLocalCalloc (sizeof (Cache->Next) + 109 (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE)); 110 111 /* Link new cache buffer to head of list */ 112 113 Cache->Next = Gbl_ParseOpCacheList; 114 Gbl_ParseOpCacheList = Cache; 115 116 /* Setup cache management pointers */ 117 118 Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer); 119 Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE; 120 } 121 122 Gbl_ParseOpCount++; 123 return (Gbl_ParseOpCacheNext++); 124 } 125 126 127 /******************************************************************************* 128 * 129 * FUNCTION: TrAllocateNode 130 * 131 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 132 * 133 * RETURN: New parse node. Aborts on allocation failure 134 * 135 * DESCRIPTION: Allocate and initialize a new parse node for the parse tree 136 * 137 ******************************************************************************/ 138 139 ACPI_PARSE_OBJECT * 140 TrAllocateNode ( 141 UINT32 ParseOpcode) 142 { 143 ACPI_PARSE_OBJECT *Op; 144 ACPI_PARSE_OBJECT *LatestNode; 145 146 147 Op = TrGetNextNode (); 148 149 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 150 Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename; 151 Op->Asl.LineNumber = Gbl_CurrentLineNumber; 152 Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber; 153 Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset; 154 Op->Asl.Column = Gbl_CurrentColumn; 155 156 UtSetParseOpName (Op); 157 158 /* The following is for capturing comments */ 159 160 if(Gbl_CaptureComments) 161 { 162 LatestNode = Gbl_CommentState.Latest_Parse_Node; 163 Op->Asl.InlineComment = NULL; 164 Op->Asl.EndNodeComment = NULL; 165 Op->Asl.CommentList = NULL; 166 Op->Asl.FileChanged = FALSE; 167 168 /* 169 * Check to see if the file name has changed before resetting the 170 * latest parse node. 171 */ 172 if (LatestNode && 173 (ParseOpcode != PARSEOP_INCLUDE) && 174 (ParseOpcode != PARSEOP_INCLUDE_END) && 175 strcmp (LatestNode->Asl.Filename, Op->Asl.Filename)) 176 { 177 CvDbgPrint ("latest node: %s\n", LatestNode->Asl.ParseOpName); 178 Op->Asl.FileChanged = TRUE; 179 if (Gbl_IncludeFileStack) 180 { 181 Op->Asl.ParentFilename = Gbl_IncludeFileStack->Filename; 182 } 183 else 184 { 185 Op->Asl.ParentFilename = NULL; 186 } 187 } 188 189 Gbl_CommentState.Latest_Parse_Node = Op; 190 if (Gbl_CommentState.Latest_Parse_Node->Asl.ParseOpName) 191 { 192 CvDbgPrint ("trallocatenode=Set latest parse node to this node.\n"); 193 CvDbgPrint (" Op->Asl.ParseOpName = %s\n", 194 Gbl_CommentState.Latest_Parse_Node->Asl.ParseOpName); 195 CvDbgPrint (" Op->Asl.ParseOpcode = 0x%x\n", ParseOpcode); 196 197 if (Op->Asl.FileChanged) 198 { 199 CvDbgPrint(" file has been changed!\n"); 200 } 201 } 202 203 /* 204 * if this parse op's syntax uses () and {} (i.e. Package(1){0x00}) then 205 * set a flag in the comment state. This facilitates paring comments for 206 * these types of opcodes. 207 */ 208 if ((CvParseOpBlockType(Op) == (BLOCK_PAREN | BLOCK_BRACE)) && 209 (ParseOpcode != PARSEOP_DEFINITION_BLOCK)) 210 { 211 CvDbgPrint ("Parsing paren/Brace node now!\n"); 212 Gbl_CommentState.ParsingParenBraceNode = Op; 213 } 214 215 if (Gbl_Comment_List_Head) 216 { 217 CvDbgPrint ("Transferring...\n"); 218 Op->Asl.CommentList = Gbl_Comment_List_Head; 219 Gbl_Comment_List_Head = NULL; 220 Gbl_Comment_List_Tail = NULL; 221 CvDbgPrint (" Transferred current comment list to this node.\n"); 222 CvDbgPrint (" %s\n", Op->Asl.CommentList->Comment); 223 } 224 if (Gbl_Inline_Comment_Buffer) 225 { 226 Op->Asl.InlineComment = Gbl_Inline_Comment_Buffer; 227 Gbl_Inline_Comment_Buffer = NULL; 228 CvDbgPrint ("Transferred current inline comment list to this node.\n"); 229 } 230 231 } 232 233 return (Op); 234 } 235 236 237 /******************************************************************************* 238 * 239 * FUNCTION: TrReleaseNode 240 * 241 * PARAMETERS: Op - Op to be released 242 * 243 * RETURN: None 244 * 245 * DESCRIPTION: "release" a node. In truth, nothing is done since the node 246 * is part of a larger buffer 247 * 248 ******************************************************************************/ 249 250 void 251 TrReleaseNode ( 252 ACPI_PARSE_OBJECT *Op) 253 { 254 255 return; 256 } 257 258 259 /******************************************************************************* 260 * 261 * FUNCTION: TrSetCurrentFilename 262 * 263 * PARAMETERS: Op - An existing parse node 264 * 265 * RETURN: None 266 * 267 * DESCRIPTION: Save the include file filename. Used for debug output only. 268 * 269 ******************************************************************************/ 270 271 void 272 TrSetCurrentFilename ( 273 ACPI_PARSE_OBJECT *Op) 274 { 275 Op->Asl.Filename = Gbl_PreviousIncludeFilename; 276 } 277 278 279 /******************************************************************************* 280 * 281 * FUNCTION: TrUpdateNode 282 * 283 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 284 * Op - An existing parse node 285 * 286 * RETURN: The updated node 287 * 288 * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to 289 * change an opcode to DEFAULT_ARG so that the node is ignored 290 * during the code generation. Also used to set generic integers 291 * to a specific size (8, 16, 32, or 64 bits) 292 * 293 ******************************************************************************/ 294 295 ACPI_PARSE_OBJECT * 296 TrUpdateNode ( 297 UINT32 ParseOpcode, 298 ACPI_PARSE_OBJECT *Op) 299 { 300 301 if (!Op) 302 { 303 return (NULL); 304 } 305 306 DbgPrint (ASL_PARSE_OUTPUT, 307 "\nUpdateNode: Old - %s, New - %s\n", 308 UtGetOpName (Op->Asl.ParseOpcode), 309 UtGetOpName (ParseOpcode)); 310 311 /* Assign new opcode and name */ 312 313 if (Op->Asl.ParseOpcode == PARSEOP_ONES) 314 { 315 switch (ParseOpcode) 316 { 317 case PARSEOP_BYTECONST: 318 319 Op->Asl.Value.Integer = ACPI_UINT8_MAX; 320 break; 321 322 case PARSEOP_WORDCONST: 323 324 Op->Asl.Value.Integer = ACPI_UINT16_MAX; 325 break; 326 327 case PARSEOP_DWORDCONST: 328 329 Op->Asl.Value.Integer = ACPI_UINT32_MAX; 330 break; 331 332 /* Don't need to do the QWORD case */ 333 334 default: 335 336 /* Don't care about others */ 337 break; 338 } 339 } 340 341 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 342 UtSetParseOpName (Op); 343 344 /* 345 * For the BYTE, WORD, and DWORD constants, make sure that the integer 346 * that was passed in will actually fit into the data type 347 */ 348 switch (ParseOpcode) 349 { 350 case PARSEOP_BYTECONST: 351 352 UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); 353 Op->Asl.Value.Integer &= ACPI_UINT8_MAX; 354 break; 355 356 case PARSEOP_WORDCONST: 357 358 UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); 359 Op->Asl.Value.Integer &= ACPI_UINT16_MAX; 360 break; 361 362 case PARSEOP_DWORDCONST: 363 364 UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); 365 Op->Asl.Value.Integer &= ACPI_UINT32_MAX; 366 break; 367 368 default: 369 370 /* Don't care about others, don't need to check QWORD */ 371 372 break; 373 } 374 375 /* Converter: if this is a method invocation, turn off capture comments. */ 376 if (Gbl_CaptureComments && 377 (ParseOpcode == PARSEOP_METHODCALL)) 378 { 379 Gbl_CommentState.CaptureComments = FALSE; 380 } 381 382 return (Op); 383 } 384 385 386 /******************************************************************************* 387 * 388 * FUNCTION: TrPrintNodeCompileFlags 389 * 390 * PARAMETERS: Flags - Flags word to be decoded 391 * 392 * RETURN: None 393 * 394 * DESCRIPTION: Decode a flags word to text. Displays all flags that are set. 395 * 396 ******************************************************************************/ 397 398 void 399 TrPrintNodeCompileFlags ( 400 UINT32 Flags) 401 { 402 UINT32 i; 403 UINT32 FlagBit = 1; 404 char *FlagName = NULL; 405 406 407 for (i = 0; i < 32; i++) 408 { 409 switch (Flags & FlagBit) 410 { 411 case NODE_VISITED: 412 413 FlagName = "NODE_VISITED"; 414 break; 415 416 case NODE_AML_PACKAGE: 417 418 FlagName = "NODE_AML_PACKAGE"; 419 break; 420 421 case NODE_IS_TARGET: 422 423 FlagName = "NODE_IS_TARGET"; 424 break; 425 426 case NODE_IS_RESOURCE_DESC: 427 428 FlagName = "NODE_IS_RESOURCE_DESC"; 429 break; 430 431 case NODE_IS_RESOURCE_FIELD: 432 433 FlagName = "NODE_IS_RESOURCE_FIELD"; 434 break; 435 436 case NODE_HAS_NO_EXIT: 437 438 FlagName = "NODE_HAS_NO_EXIT"; 439 break; 440 441 case NODE_IF_HAS_NO_EXIT: 442 443 FlagName = "NODE_IF_HAS_NO_EXIT"; 444 break; 445 446 case NODE_NAME_INTERNALIZED: 447 448 FlagName = "NODE_NAME_INTERNALIZED"; 449 break; 450 451 case NODE_METHOD_NO_RETVAL: 452 453 FlagName = "NODE_METHOD_NO_RETVAL"; 454 break; 455 456 case NODE_METHOD_SOME_NO_RETVAL: 457 458 FlagName = "NODE_METHOD_SOME_NO_RETVAL"; 459 break; 460 461 case NODE_RESULT_NOT_USED: 462 463 FlagName = "NODE_RESULT_NOT_USED"; 464 break; 465 466 case NODE_METHOD_TYPED: 467 468 FlagName = "NODE_METHOD_TYPED"; 469 break; 470 471 case NODE_COULD_NOT_REDUCE: 472 473 FlagName = "NODE_COULD_NOT_REDUCE"; 474 break; 475 476 case NODE_COMPILE_TIME_CONST: 477 478 FlagName = "NODE_COMPILE_TIME_CONST"; 479 break; 480 481 case NODE_IS_TERM_ARG: 482 483 FlagName = "NODE_IS_TERM_ARG"; 484 break; 485 486 case NODE_WAS_ONES_OP: 487 488 FlagName = "NODE_WAS_ONES_OP"; 489 break; 490 491 case NODE_IS_NAME_DECLARATION: 492 493 FlagName = "NODE_IS_NAME_DECLARATION"; 494 break; 495 496 case NODE_COMPILER_EMITTED: 497 498 FlagName = "NODE_COMPILER_EMITTED"; 499 break; 500 501 case NODE_IS_DUPLICATE: 502 503 FlagName = "NODE_IS_DUPLICATE"; 504 break; 505 506 case NODE_IS_RESOURCE_DATA: 507 508 FlagName = "NODE_IS_RESOURCE_DATA"; 509 break; 510 511 case NODE_IS_NULL_RETURN: 512 513 FlagName = "NODE_IS_NULL_RETURN"; 514 break; 515 516 default: 517 break; 518 } 519 520 if (FlagName) 521 { 522 DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName); 523 FlagName = NULL; 524 } 525 526 FlagBit <<= 1; 527 } 528 } 529 530 531 /******************************************************************************* 532 * 533 * FUNCTION: TrSetNodeFlags 534 * 535 * PARAMETERS: Op - An existing parse node 536 * Flags - New flags word 537 * 538 * RETURN: The updated parser op 539 * 540 * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set 541 * 542 ******************************************************************************/ 543 544 ACPI_PARSE_OBJECT * 545 TrSetNodeFlags ( 546 ACPI_PARSE_OBJECT *Op, 547 UINT32 Flags) 548 { 549 550 if (!Op) 551 { 552 return (NULL); 553 } 554 555 DbgPrint (ASL_PARSE_OUTPUT, 556 "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags); 557 558 TrPrintNodeCompileFlags (Flags); 559 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 560 561 Op->Asl.CompileFlags |= Flags; 562 return (Op); 563 } 564 565 566 /******************************************************************************* 567 * 568 * FUNCTION: TrSetNodeAmlLength 569 * 570 * PARAMETERS: Op - An existing parse node 571 * Length - AML Length 572 * 573 * RETURN: The updated parser op 574 * 575 * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate 576 * the presence of a node that must be reduced to a fixed length 577 * constant. 578 * 579 ******************************************************************************/ 580 581 ACPI_PARSE_OBJECT * 582 TrSetNodeAmlLength ( 583 ACPI_PARSE_OBJECT *Op, 584 UINT32 Length) 585 { 586 587 DbgPrint (ASL_PARSE_OUTPUT, 588 "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length); 589 590 if (!Op) 591 { 592 return (NULL); 593 } 594 595 Op->Asl.AmlLength = Length; 596 return (Op); 597 } 598 599 600 /******************************************************************************* 601 * 602 * FUNCTION: TrSetEndLineNumber 603 * 604 * PARAMETERS: Op - An existing parse node 605 * 606 * RETURN: None. 607 * 608 * DESCRIPTION: Set the ending line numbers (file line and logical line) of a 609 * parse node to the current line numbers. 610 * 611 ******************************************************************************/ 612 613 void 614 TrSetEndLineNumber ( 615 ACPI_PARSE_OBJECT *Op) 616 { 617 618 /* If the end line # is already set, just return */ 619 620 if (Op->Asl.EndLine) 621 { 622 return; 623 } 624 625 Op->Asl.EndLine = Gbl_CurrentLineNumber; 626 Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber; 627 } 628 629 630 /******************************************************************************* 631 * 632 * FUNCTION: TrCreateAssignmentNode 633 * 634 * PARAMETERS: Target - Assignment target 635 * Source - Assignment source 636 * 637 * RETURN: Pointer to the new node. Aborts on allocation failure 638 * 639 * DESCRIPTION: Implements the C-style '=' operator. It changes the parse 640 * tree if possible to utilize the last argument of the math 641 * operators which is a target operand -- thus saving invocation 642 * of and additional Store() operator. An optimization. 643 * 644 ******************************************************************************/ 645 646 ACPI_PARSE_OBJECT * 647 TrCreateAssignmentNode ( 648 ACPI_PARSE_OBJECT *Target, 649 ACPI_PARSE_OBJECT *Source) 650 { 651 ACPI_PARSE_OBJECT *TargetOp; 652 ACPI_PARSE_OBJECT *SourceOp1; 653 ACPI_PARSE_OBJECT *SourceOp2; 654 ACPI_PARSE_OBJECT *Operator; 655 656 657 DbgPrint (ASL_PARSE_OUTPUT, 658 "\nTrCreateAssignmentNode Line [%u to %u] Source %s Target %s\n", 659 Source->Asl.LineNumber, Source->Asl.EndLine, 660 UtGetOpName (Source->Asl.ParseOpcode), 661 UtGetOpName (Target->Asl.ParseOpcode)); 662 663 TrSetNodeFlags (Target, NODE_IS_TARGET); 664 665 switch (Source->Asl.ParseOpcode) 666 { 667 /* 668 * Only these operators can be optimized because they have 669 * a target operand 670 */ 671 case PARSEOP_ADD: 672 case PARSEOP_AND: 673 case PARSEOP_DIVIDE: 674 case PARSEOP_INDEX: 675 case PARSEOP_MOD: 676 case PARSEOP_MULTIPLY: 677 case PARSEOP_NOT: 678 case PARSEOP_OR: 679 case PARSEOP_SHIFTLEFT: 680 case PARSEOP_SHIFTRIGHT: 681 case PARSEOP_SUBTRACT: 682 case PARSEOP_XOR: 683 684 break; 685 686 /* Otherwise, just create a normal Store operator */ 687 688 default: 689 690 goto CannotOptimize; 691 } 692 693 /* 694 * Transform the parse tree such that the target is moved to the 695 * last operand of the operator 696 */ 697 SourceOp1 = Source->Asl.Child; 698 SourceOp2 = SourceOp1->Asl.Next; 699 700 /* NOT only has one operand, but has a target */ 701 702 if (Source->Asl.ParseOpcode == PARSEOP_NOT) 703 { 704 SourceOp2 = SourceOp1; 705 } 706 707 /* DIVIDE has an extra target operand (remainder) */ 708 709 if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE) 710 { 711 SourceOp2 = SourceOp2->Asl.Next; 712 } 713 714 TargetOp = SourceOp2->Asl.Next; 715 716 /* 717 * Can't perform this optimization if there already is a target 718 * for the operator (ZERO is a "no target" placeholder). 719 */ 720 if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO) 721 { 722 goto CannotOptimize; 723 } 724 725 /* Link in the target as the final operand */ 726 727 SourceOp2->Asl.Next = Target; 728 Target->Asl.Parent = Source; 729 730 return (Source); 731 732 733 CannotOptimize: 734 735 Operator = TrAllocateNode (PARSEOP_STORE); 736 TrLinkChildren (Operator, 2, Source, Target); 737 738 /* Set the appropriate line numbers for the new node */ 739 740 Operator->Asl.LineNumber = Target->Asl.LineNumber; 741 Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber; 742 Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset; 743 Operator->Asl.Column = Target->Asl.Column; 744 745 return (Operator); 746 } 747 748 749 /******************************************************************************* 750 * 751 * FUNCTION: TrCreateLeafNode 752 * 753 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 754 * 755 * RETURN: Pointer to the new node. Aborts on allocation failure 756 * 757 * DESCRIPTION: Create a simple leaf node (no children or peers, and no value 758 * assigned to the node) 759 * 760 ******************************************************************************/ 761 762 ACPI_PARSE_OBJECT * 763 TrCreateLeafNode ( 764 UINT32 ParseOpcode) 765 { 766 ACPI_PARSE_OBJECT *Op; 767 768 769 Op = TrAllocateNode (ParseOpcode); 770 771 DbgPrint (ASL_PARSE_OUTPUT, 772 "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n", 773 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode)); 774 775 return (Op); 776 } 777 778 779 /******************************************************************************* 780 * 781 * FUNCTION: TrCreateNullTarget 782 * 783 * PARAMETERS: None 784 * 785 * RETURN: Pointer to the new node. Aborts on allocation failure 786 * 787 * DESCRIPTION: Create a "null" target node. This is defined by the ACPI 788 * specification to be a zero AML opcode, and indicates that 789 * no target has been specified for the parent operation 790 * 791 ******************************************************************************/ 792 793 ACPI_PARSE_OBJECT * 794 TrCreateNullTarget ( 795 void) 796 { 797 ACPI_PARSE_OBJECT *Op; 798 799 800 Op = TrAllocateNode (PARSEOP_ZERO); 801 Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST); 802 803 DbgPrint (ASL_PARSE_OUTPUT, 804 "\nCreateNullTarget Ln/Col %u/%u NewNode %p Op %s\n", 805 Op->Asl.LineNumber, Op->Asl.Column, Op, 806 UtGetOpName (Op->Asl.ParseOpcode)); 807 808 return (Op); 809 } 810 811 812 /******************************************************************************* 813 * 814 * FUNCTION: TrCreateConstantLeafNode 815 * 816 * PARAMETERS: ParseOpcode - The constant opcode 817 * 818 * RETURN: Pointer to the new node. Aborts on allocation failure 819 * 820 * DESCRIPTION: Create a leaf node (no children or peers) for one of the 821 * special constants - __LINE__, __FILE__, and __DATE__. 822 * 823 * Note: An implemenation of __FUNC__ cannot happen here because we don't 824 * have a full parse tree at this time and cannot find the parent control 825 * method. If it is ever needed, __FUNC__ must be implemented later, after 826 * the parse tree has been fully constructed. 827 * 828 ******************************************************************************/ 829 830 ACPI_PARSE_OBJECT * 831 TrCreateConstantLeafNode ( 832 UINT32 ParseOpcode) 833 { 834 ACPI_PARSE_OBJECT *Op = NULL; 835 time_t CurrentTime; 836 char *StaticTimeString; 837 char *TimeString; 838 char *Filename; 839 840 841 switch (ParseOpcode) 842 { 843 case PARSEOP___LINE__: 844 845 Op = TrAllocateNode (PARSEOP_INTEGER); 846 Op->Asl.Value.Integer = Op->Asl.LineNumber; 847 break; 848 849 case PARSEOP___PATH__: 850 851 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 852 853 /* Op.Asl.Filename contains the full pathname to the file */ 854 855 Op->Asl.Value.String = Op->Asl.Filename; 856 break; 857 858 case PARSEOP___FILE__: 859 860 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 861 862 /* Get the simple filename from the full path */ 863 864 FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename); 865 Op->Asl.Value.String = Filename; 866 break; 867 868 case PARSEOP___DATE__: 869 870 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 871 872 /* Get a copy of the current time */ 873 874 CurrentTime = time (NULL); 875 StaticTimeString = ctime (&CurrentTime); 876 TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1); 877 strcpy (TimeString, StaticTimeString); 878 879 TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */ 880 Op->Asl.Value.String = TimeString; 881 break; 882 883 default: /* This would be an internal error */ 884 885 return (NULL); 886 } 887 888 DbgPrint (ASL_PARSE_OUTPUT, 889 "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p " 890 "Op %s Value %8.8X%8.8X \n", 891 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode), 892 ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer)); 893 return (Op); 894 } 895 896 897 /******************************************************************************* 898 * 899 * FUNCTION: TrCreateTargetOperand 900 * 901 * PARAMETERS: OriginalOp - Op to be copied 902 * 903 * RETURN: Pointer to the new node. Aborts on allocation failure 904 * 905 * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style) 906 * expressions where the target is the same as one of the 907 * operands. A new node and subtree must be created from the 908 * original so that the parse tree can be linked properly. 909 * 910 * NOTE: This code is specific to target operands that are the last 911 * operand in an ASL/AML operator. Meaning that the top-level 912 * parse Op in a possible subtree has a NULL Next pointer. 913 * This simplifies the recursion. 914 * 915 * Subtree example: 916 * DeRefOf (Local1) += 32 917 * 918 * This gets converted to: 919 * Add (DeRefOf (Local1), 32, DeRefOf (Local1)) 920 * 921 * Each DeRefOf has a single child, Local1. Even more complex 922 * subtrees can be created via the Index and DeRefOf operators. 923 * 924 ******************************************************************************/ 925 926 ACPI_PARSE_OBJECT * 927 TrCreateTargetOperand ( 928 ACPI_PARSE_OBJECT *OriginalOp, 929 ACPI_PARSE_OBJECT *ParentOp) 930 { 931 ACPI_PARSE_OBJECT *Op; 932 933 934 if (!OriginalOp) 935 { 936 return (NULL); 937 } 938 939 Op = TrGetNextNode (); 940 941 /* Copy the pertinent values (omit link pointer fields) */ 942 943 Op->Asl.Value = OriginalOp->Asl.Value; 944 Op->Asl.Filename = OriginalOp->Asl.Filename; 945 Op->Asl.LineNumber = OriginalOp->Asl.LineNumber; 946 Op->Asl.LogicalLineNumber = OriginalOp->Asl.LogicalLineNumber; 947 Op->Asl.LogicalByteOffset = OriginalOp->Asl.LogicalByteOffset; 948 Op->Asl.Column = OriginalOp->Asl.Column; 949 Op->Asl.Flags = OriginalOp->Asl.Flags; 950 Op->Asl.CompileFlags = OriginalOp->Asl.CompileFlags; 951 Op->Asl.AmlOpcode = OriginalOp->Asl.AmlOpcode; 952 Op->Asl.ParseOpcode = OriginalOp->Asl.ParseOpcode; 953 Op->Asl.Parent = ParentOp; 954 UtSetParseOpName (Op); 955 956 /* Copy a possible subtree below this node */ 957 958 if (OriginalOp->Asl.Child) 959 { 960 Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op); 961 } 962 963 if (OriginalOp->Asl.Next) /* Null for top-level node */ 964 { 965 Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp); 966 } 967 968 return (Op); 969 } 970 971 972 /******************************************************************************* 973 * 974 * FUNCTION: TrCreateValuedLeafNode 975 * 976 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 977 * Value - Value to be assigned to the node 978 * 979 * RETURN: Pointer to the new node. Aborts on allocation failure 980 * 981 * DESCRIPTION: Create a leaf node (no children or peers) with a value 982 * assigned to it 983 * 984 ******************************************************************************/ 985 986 ACPI_PARSE_OBJECT * 987 TrCreateValuedLeafNode ( 988 UINT32 ParseOpcode, 989 UINT64 Value) 990 { 991 ACPI_PARSE_OBJECT *Op; 992 993 994 Op = TrAllocateNode (ParseOpcode); 995 996 DbgPrint (ASL_PARSE_OUTPUT, 997 "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p " 998 "Op %s Value %8.8X%8.8X ", 999 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode), 1000 ACPI_FORMAT_UINT64 (Value)); 1001 Op->Asl.Value.Integer = Value; 1002 1003 switch (ParseOpcode) 1004 { 1005 case PARSEOP_STRING_LITERAL: 1006 1007 DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value); 1008 break; 1009 1010 case PARSEOP_NAMESEG: 1011 1012 DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value); 1013 break; 1014 1015 case PARSEOP_NAMESTRING: 1016 1017 DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value); 1018 break; 1019 1020 case PARSEOP_EISAID: 1021 1022 DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value); 1023 break; 1024 1025 case PARSEOP_METHOD: 1026 1027 DbgPrint (ASL_PARSE_OUTPUT, "METHOD"); 1028 break; 1029 1030 case PARSEOP_INTEGER: 1031 1032 DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X", 1033 ACPI_FORMAT_UINT64 (Value)); 1034 break; 1035 1036 default: 1037 1038 break; 1039 } 1040 1041 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 1042 return (Op); 1043 } 1044 1045 1046 /******************************************************************************* 1047 * 1048 * FUNCTION: TrCreateNode 1049 * 1050 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 1051 * NumChildren - Number of children to follow 1052 * ... - A list of child nodes to link to the new 1053 * node. NumChildren long. 1054 * 1055 * RETURN: Pointer to the new node. Aborts on allocation failure 1056 * 1057 * DESCRIPTION: Create a new parse node and link together a list of child 1058 * nodes underneath the new node. 1059 * 1060 ******************************************************************************/ 1061 1062 ACPI_PARSE_OBJECT * 1063 TrCreateNode ( 1064 UINT32 ParseOpcode, 1065 UINT32 NumChildren, 1066 ...) 1067 { 1068 ACPI_PARSE_OBJECT *Op; 1069 ACPI_PARSE_OBJECT *Child; 1070 ACPI_PARSE_OBJECT *PrevChild; 1071 va_list ap; 1072 UINT32 i; 1073 BOOLEAN FirstChild; 1074 1075 1076 va_start (ap, NumChildren); 1077 1078 /* Allocate one new node */ 1079 1080 Op = TrAllocateNode (ParseOpcode); 1081 1082 DbgPrint (ASL_PARSE_OUTPUT, 1083 "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ", 1084 Op->Asl.LineNumber, Op->Asl.Column, Op, 1085 NumChildren, UtGetOpName(ParseOpcode)); 1086 1087 /* Some extra debug output based on the parse opcode */ 1088 1089 switch (ParseOpcode) 1090 { 1091 case PARSEOP_ASL_CODE: 1092 1093 Gbl_ParseTreeRoot = Op; 1094 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1095 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 1096 break; 1097 1098 case PARSEOP_DEFINITION_BLOCK: 1099 1100 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 1101 break; 1102 1103 case PARSEOP_OPERATIONREGION: 1104 1105 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 1106 break; 1107 1108 case PARSEOP_OR: 1109 1110 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 1111 break; 1112 1113 default: 1114 1115 /* Nothing to do for other opcodes */ 1116 1117 break; 1118 } 1119 1120 /* Link the new node to its children */ 1121 1122 PrevChild = NULL; 1123 FirstChild = TRUE; 1124 for (i = 0; i < NumChildren; i++) 1125 { 1126 /* Get the next child */ 1127 1128 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 1129 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 1130 1131 /* 1132 * If child is NULL, this means that an optional argument 1133 * was omitted. We must create a placeholder with a special 1134 * opcode (DEFAULT_ARG) so that the code generator will know 1135 * that it must emit the correct default for this argument 1136 */ 1137 if (!Child) 1138 { 1139 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1140 } 1141 1142 /* Link first child to parent */ 1143 1144 if (FirstChild) 1145 { 1146 FirstChild = FALSE; 1147 Op->Asl.Child = Child; 1148 1149 /* 1150 * For the ASL-/ASL+ converter: if the ParseOp is a connection, 1151 * external, offset or accessAs, it means that the comments in the 1152 * FirstChild belongs to their parent due to the parsing order in 1153 * the .y files. To correct this, take the comments in the 1154 * FirstChild place it in the parent. This also means that 1155 * legitimate comments for the child gets put to the parent. 1156 */ 1157 if (Gbl_CaptureComments && 1158 ((ParseOpcode == PARSEOP_CONNECTION) || 1159 (ParseOpcode == PARSEOP_EXTERNAL) || 1160 (ParseOpcode == PARSEOP_OFFSET) || 1161 (ParseOpcode == PARSEOP_ACCESSAS))) 1162 { 1163 Op->Asl.CommentList = Child->Asl.CommentList; 1164 Op->Asl.EndBlkComment = Child->Asl.EndBlkComment; 1165 Op->Asl.InlineComment = Child->Asl.InlineComment; 1166 Op->Asl.FileChanged = Child->Asl.FileChanged; 1167 1168 Child->Asl.CommentList = NULL; 1169 Child->Asl.EndBlkComment = NULL; 1170 Child->Asl.InlineComment = NULL; 1171 Child->Asl.FileChanged = FALSE; 1172 1173 /* 1174 * These do not need to be "passed off". They can be copied 1175 * because the code for these opcodes should be printed in the 1176 * same file. 1177 */ 1178 Op->Asl.Filename = Child->Asl.Filename; 1179 Op->Asl.ParentFilename = Child->Asl.ParentFilename; 1180 } 1181 } 1182 1183 /* Point all children to parent */ 1184 1185 Child->Asl.Parent = Op; 1186 1187 /* Link children in a peer list */ 1188 1189 if (PrevChild) 1190 { 1191 PrevChild->Asl.Next = Child; 1192 }; 1193 1194 /* Get the comment from last child in the resource template call */ 1195 1196 if (Gbl_CaptureComments && 1197 (Op->Asl.ParseOpcode == PARSEOP_RESOURCETEMPLATE)) 1198 { 1199 CvDbgPrint ("Transferred current comment list to this node.\n"); 1200 Op->Asl.CommentList = Child->Asl.CommentList; 1201 Child->Asl.CommentList = NULL; 1202 Op->Asl.InlineComment = Child->Asl.InlineComment; 1203 Child->Asl.InlineComment = NULL; 1204 } 1205 1206 /* 1207 * This child might be a list, point all nodes in the list 1208 * to the same parent 1209 */ 1210 while (Child->Asl.Next) 1211 { 1212 Child = Child->Asl.Next; 1213 Child->Asl.Parent = Op; 1214 } 1215 1216 PrevChild = Child; 1217 } 1218 va_end(ap); 1219 1220 DbgPrint (ASL_PARSE_OUTPUT, "\n"); 1221 return (Op); 1222 } 1223 1224 1225 /******************************************************************************* 1226 * 1227 * FUNCTION: TrLinkChildren 1228 * 1229 * PARAMETERS: Op - An existing parse node 1230 * NumChildren - Number of children to follow 1231 * ... - A list of child nodes to link to the new 1232 * node. NumChildren long. 1233 * 1234 * RETURN: The updated (linked) node 1235 * 1236 * DESCRIPTION: Link a group of nodes to an existing parse node 1237 * 1238 ******************************************************************************/ 1239 1240 ACPI_PARSE_OBJECT * 1241 TrLinkChildren ( 1242 ACPI_PARSE_OBJECT *Op, 1243 UINT32 NumChildren, 1244 ...) 1245 { 1246 ACPI_PARSE_OBJECT *Child; 1247 ACPI_PARSE_OBJECT *PrevChild; 1248 va_list ap; 1249 UINT32 i; 1250 BOOLEAN FirstChild; 1251 1252 1253 va_start (ap, NumChildren); 1254 1255 1256 TrSetEndLineNumber (Op); 1257 1258 DbgPrint (ASL_PARSE_OUTPUT, 1259 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", 1260 Op->Asl.LineNumber, Op->Asl.EndLine, 1261 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); 1262 1263 switch (Op->Asl.ParseOpcode) 1264 { 1265 case PARSEOP_ASL_CODE: 1266 1267 Gbl_ParseTreeRoot = Op; 1268 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1269 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 1270 break; 1271 1272 case PARSEOP_DEFINITION_BLOCK: 1273 1274 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 1275 break; 1276 1277 case PARSEOP_OPERATIONREGION: 1278 1279 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 1280 break; 1281 1282 case PARSEOP_OR: 1283 1284 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 1285 break; 1286 1287 default: 1288 1289 /* Nothing to do for other opcodes */ 1290 1291 break; 1292 } 1293 1294 /* The following is for capturing comments */ 1295 1296 if(Gbl_CaptureComments) 1297 { 1298 /* 1299 * If there are "regular comments" detected at this point, 1300 * then is an endBlk comment. Categorize it as so and distribute 1301 * all regular comments to this parse node. 1302 */ 1303 if (Gbl_Comment_List_Head) 1304 { 1305 Op->Asl.EndBlkComment = Gbl_Comment_List_Head; 1306 CvDbgPrint ("EndBlk Comment for %s: %s", 1307 Op->Asl.ParseOpName, Gbl_Comment_List_Head->Comment); 1308 Gbl_Comment_List_Head = NULL; 1309 Gbl_Comment_List_Tail = NULL; 1310 } 1311 } 1312 1313 /* Link the new node to it's children */ 1314 1315 PrevChild = NULL; 1316 FirstChild = TRUE; 1317 for (i = 0; i < NumChildren; i++) 1318 { 1319 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 1320 1321 if ((Child == PrevChild) && (Child != NULL)) 1322 { 1323 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, 1324 "Child node list invalid"); 1325 va_end(ap); 1326 return (Op); 1327 } 1328 1329 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 1330 1331 /* 1332 * If child is NULL, this means that an optional argument 1333 * was omitted. We must create a placeholder with a special 1334 * opcode (DEFAULT_ARG) so that the code generator will know 1335 * that it must emit the correct default for this argument 1336 */ 1337 if (!Child) 1338 { 1339 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1340 } 1341 1342 /* Link first child to parent */ 1343 1344 if (FirstChild) 1345 { 1346 FirstChild = FALSE; 1347 Op->Asl.Child = Child; 1348 } 1349 1350 /* Point all children to parent */ 1351 1352 Child->Asl.Parent = Op; 1353 1354 /* Link children in a peer list */ 1355 1356 if (PrevChild) 1357 { 1358 PrevChild->Asl.Next = Child; 1359 }; 1360 1361 /* 1362 * This child might be a list, point all nodes in the list 1363 * to the same parent 1364 */ 1365 while (Child->Asl.Next) 1366 { 1367 Child = Child->Asl.Next; 1368 Child->Asl.Parent = Op; 1369 } 1370 1371 PrevChild = Child; 1372 } 1373 1374 va_end(ap); 1375 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 1376 1377 1378 if(Gbl_CaptureComments) 1379 { 1380 Gbl_CommentState.Latest_Parse_Node = Op; 1381 CvDbgPrint ("trlinkchildren=====Set latest parse node to this node.\n"); 1382 } 1383 return (Op); 1384 } 1385 1386 1387 /******************************************************************************* 1388 * 1389 * FUNCTION: TrLinkPeerNode 1390 * 1391 * PARAMETERS: Op1 - First peer 1392 * Op2 - Second peer 1393 * 1394 * RETURN: Op1 or the non-null node. 1395 * 1396 * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. 1397 * 1398 ******************************************************************************/ 1399 1400 ACPI_PARSE_OBJECT * 1401 TrLinkPeerNode ( 1402 ACPI_PARSE_OBJECT *Op1, 1403 ACPI_PARSE_OBJECT *Op2) 1404 { 1405 ACPI_PARSE_OBJECT *Next; 1406 1407 1408 DbgPrint (ASL_PARSE_OUTPUT, 1409 "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n", 1410 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, 1411 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); 1412 1413 1414 if ((!Op1) && (!Op2)) 1415 { 1416 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n"); 1417 return (Op1); 1418 } 1419 1420 /* If one of the nodes is null, just return the non-null node */ 1421 1422 if (!Op2) 1423 { 1424 return (Op1); 1425 } 1426 1427 if (!Op1) 1428 { 1429 return (Op2); 1430 } 1431 1432 if (Op1 == Op2) 1433 { 1434 DbgPrint (ASL_DEBUG_OUTPUT, 1435 "\n************* Internal error, linking node to itself %p\n", 1436 Op1); 1437 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, 1438 "Linking node to itself"); 1439 return (Op1); 1440 } 1441 1442 Op1->Asl.Parent = Op2->Asl.Parent; 1443 1444 /* 1445 * Op 1 may already have a peer list (such as an IF/ELSE pair), 1446 * so we must walk to the end of the list and attach the new 1447 * peer at the end 1448 */ 1449 Next = Op1; 1450 while (Next->Asl.Next) 1451 { 1452 Next = Next->Asl.Next; 1453 } 1454 1455 Next->Asl.Next = Op2; 1456 return (Op1); 1457 } 1458 1459 1460 /******************************************************************************* 1461 * 1462 * FUNCTION: TrLinkPeerNodes 1463 * 1464 * PARAMETERS: NumPeers - The number of nodes in the list to follow 1465 * ... - A list of nodes to link together as peers 1466 * 1467 * RETURN: The first node in the list (head of the peer list) 1468 * 1469 * DESCRIPTION: Link together an arbitrary number of peer nodes. 1470 * 1471 ******************************************************************************/ 1472 1473 ACPI_PARSE_OBJECT * 1474 TrLinkPeerNodes ( 1475 UINT32 NumPeers, 1476 ...) 1477 { 1478 ACPI_PARSE_OBJECT *This; 1479 ACPI_PARSE_OBJECT *Next; 1480 va_list ap; 1481 UINT32 i; 1482 ACPI_PARSE_OBJECT *Start; 1483 1484 1485 DbgPrint (ASL_PARSE_OUTPUT, 1486 "\nLinkPeerNodes: (%u) ", NumPeers); 1487 1488 va_start (ap, NumPeers); 1489 This = va_arg (ap, ACPI_PARSE_OBJECT *); 1490 Start = This; 1491 1492 /* 1493 * Link all peers 1494 */ 1495 for (i = 0; i < (NumPeers -1); i++) 1496 { 1497 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); 1498 1499 while (This->Asl.Next) 1500 { 1501 This = This->Asl.Next; 1502 } 1503 1504 /* Get another peer node */ 1505 1506 Next = va_arg (ap, ACPI_PARSE_OBJECT *); 1507 if (!Next) 1508 { 1509 Next = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1510 } 1511 1512 /* link new node to the current node */ 1513 1514 This->Asl.Next = Next; 1515 This = Next; 1516 } 1517 va_end (ap); 1518 1519 DbgPrint (ASL_PARSE_OUTPUT,"\n"); 1520 return (Start); 1521 } 1522 1523 1524 /******************************************************************************* 1525 * 1526 * FUNCTION: TrLinkChildNode 1527 * 1528 * PARAMETERS: Op1 - Parent node 1529 * Op2 - Op to become a child 1530 * 1531 * RETURN: The parent node 1532 * 1533 * DESCRIPTION: Link two nodes together as a parent and child 1534 * 1535 ******************************************************************************/ 1536 1537 ACPI_PARSE_OBJECT * 1538 TrLinkChildNode ( 1539 ACPI_PARSE_OBJECT *Op1, 1540 ACPI_PARSE_OBJECT *Op2) 1541 { 1542 ACPI_PARSE_OBJECT *Next; 1543 1544 1545 DbgPrint (ASL_PARSE_OUTPUT, 1546 "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n", 1547 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, 1548 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); 1549 1550 /* 1551 * Converter: if TrLinkChildNode is called to link a method call, 1552 * turn on capture comments as it signifies that we are done parsing 1553 * a method call. 1554 */ 1555 if (Gbl_CaptureComments) 1556 { 1557 if (Op1->Asl.ParseOpcode == PARSEOP_METHODCALL) 1558 { 1559 Gbl_CommentState.CaptureComments = TRUE; 1560 } 1561 Gbl_CommentState.Latest_Parse_Node = Op1; 1562 } 1563 if (!Op1 || !Op2) 1564 { 1565 return (Op1); 1566 } 1567 1568 Op1->Asl.Child = Op2; 1569 1570 /* Set the child and all peers of the child to point to the parent */ 1571 1572 Next = Op2; 1573 while (Next) 1574 { 1575 Next->Asl.Parent = Op1; 1576 Next = Next->Asl.Next; 1577 } 1578 1579 return (Op1); 1580 } 1581 1582 1583 /******************************************************************************* 1584 * 1585 * FUNCTION: TrWalkParseTree 1586 * 1587 * PARAMETERS: Visitation - Type of walk 1588 * DescendingCallback - Called during tree descent 1589 * AscendingCallback - Called during tree ascent 1590 * Context - To be passed to the callbacks 1591 * 1592 * RETURN: Status from callback(s) 1593 * 1594 * DESCRIPTION: Walk the entire parse tree. 1595 * 1596 ******************************************************************************/ 1597 1598 ACPI_STATUS 1599 TrWalkParseTree ( 1600 ACPI_PARSE_OBJECT *Op, 1601 UINT32 Visitation, 1602 ASL_WALK_CALLBACK DescendingCallback, 1603 ASL_WALK_CALLBACK AscendingCallback, 1604 void *Context) 1605 { 1606 UINT32 Level; 1607 BOOLEAN NodePreviouslyVisited; 1608 ACPI_PARSE_OBJECT *StartOp = Op; 1609 ACPI_STATUS Status; 1610 1611 1612 if (!Gbl_ParseTreeRoot) 1613 { 1614 return (AE_OK); 1615 } 1616 1617 Level = 0; 1618 NodePreviouslyVisited = FALSE; 1619 1620 switch (Visitation) 1621 { 1622 case ASL_WALK_VISIT_DOWNWARD: 1623 1624 while (Op) 1625 { 1626 if (!NodePreviouslyVisited) 1627 { 1628 /* Let the callback process the node. */ 1629 1630 Status = DescendingCallback (Op, Level, Context); 1631 if (ACPI_SUCCESS (Status)) 1632 { 1633 /* Visit children first, once */ 1634 1635 if (Op->Asl.Child) 1636 { 1637 Level++; 1638 Op = Op->Asl.Child; 1639 continue; 1640 } 1641 } 1642 else if (Status != AE_CTRL_DEPTH) 1643 { 1644 /* Exit immediately on any error */ 1645 1646 return (Status); 1647 } 1648 } 1649 1650 /* Terminate walk at start op */ 1651 1652 if (Op == StartOp) 1653 { 1654 break; 1655 } 1656 1657 /* No more children, visit peers */ 1658 1659 if (Op->Asl.Next) 1660 { 1661 Op = Op->Asl.Next; 1662 NodePreviouslyVisited = FALSE; 1663 } 1664 else 1665 { 1666 /* No children or peers, re-visit parent */ 1667 1668 if (Level != 0 ) 1669 { 1670 Level--; 1671 } 1672 Op = Op->Asl.Parent; 1673 NodePreviouslyVisited = TRUE; 1674 } 1675 } 1676 break; 1677 1678 case ASL_WALK_VISIT_UPWARD: 1679 1680 while (Op) 1681 { 1682 /* Visit leaf node (no children) or parent node on return trip */ 1683 1684 if ((!Op->Asl.Child) || 1685 (NodePreviouslyVisited)) 1686 { 1687 /* Let the callback process the node. */ 1688 1689 Status = AscendingCallback (Op, Level, Context); 1690 if (ACPI_FAILURE (Status)) 1691 { 1692 return (Status); 1693 } 1694 } 1695 else 1696 { 1697 /* Visit children first, once */ 1698 1699 Level++; 1700 Op = Op->Asl.Child; 1701 continue; 1702 } 1703 1704 /* Terminate walk at start op */ 1705 1706 if (Op == StartOp) 1707 { 1708 break; 1709 } 1710 1711 /* No more children, visit peers */ 1712 1713 if (Op->Asl.Next) 1714 { 1715 Op = Op->Asl.Next; 1716 NodePreviouslyVisited = FALSE; 1717 } 1718 else 1719 { 1720 /* No children or peers, re-visit parent */ 1721 1722 if (Level != 0 ) 1723 { 1724 Level--; 1725 } 1726 Op = Op->Asl.Parent; 1727 NodePreviouslyVisited = TRUE; 1728 } 1729 } 1730 break; 1731 1732 case ASL_WALK_VISIT_TWICE: 1733 1734 while (Op) 1735 { 1736 if (NodePreviouslyVisited) 1737 { 1738 Status = AscendingCallback (Op, Level, Context); 1739 if (ACPI_FAILURE (Status)) 1740 { 1741 return (Status); 1742 } 1743 } 1744 else 1745 { 1746 /* Let the callback process the node. */ 1747 1748 Status = DescendingCallback (Op, Level, Context); 1749 if (ACPI_SUCCESS (Status)) 1750 { 1751 /* Visit children first, once */ 1752 1753 if (Op->Asl.Child) 1754 { 1755 Level++; 1756 Op = Op->Asl.Child; 1757 continue; 1758 } 1759 } 1760 else if (Status != AE_CTRL_DEPTH) 1761 { 1762 /* Exit immediately on any error */ 1763 1764 return (Status); 1765 } 1766 } 1767 1768 /* Terminate walk at start op */ 1769 1770 if (Op == StartOp) 1771 { 1772 break; 1773 } 1774 1775 /* No more children, visit peers */ 1776 1777 if (Op->Asl.Next) 1778 { 1779 Op = Op->Asl.Next; 1780 NodePreviouslyVisited = FALSE; 1781 } 1782 else 1783 { 1784 /* No children or peers, re-visit parent */ 1785 1786 if (Level != 0 ) 1787 { 1788 Level--; 1789 } 1790 Op = Op->Asl.Parent; 1791 NodePreviouslyVisited = TRUE; 1792 } 1793 } 1794 break; 1795 1796 default: 1797 /* No other types supported */ 1798 break; 1799 } 1800 1801 /* If we get here, the walk completed with no errors */ 1802 1803 return (AE_OK); 1804 } 1805