xref: /dflybsd-src/sys/contrib/dev/acpica/source/compiler/asltree.c (revision d638c6eedc81671c3ceddd06ef20463940cb6a43)
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