]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/dev/acpica/compiler/asltree.c
Merge ACPICA 20111123.
[FreeBSD/FreeBSD.git] / sys / contrib / dev / acpica / compiler / asltree.c
1
2 /******************************************************************************
3  *
4  * Module Name: asltree - parse tree management
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2011, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44
45
46 #include <contrib/dev/acpica/compiler/aslcompiler.h>
47 #include "aslcompiler.y.h"
48 #include <contrib/dev/acpica/include/acapps.h>
49 #include <time.h>
50
51 #define _COMPONENT          ACPI_COMPILER
52         ACPI_MODULE_NAME    ("asltree")
53
54 /* Local prototypes */
55
56 static ACPI_PARSE_OBJECT *
57 TrGetNextNode (
58     void);
59
60 static char *
61 TrGetNodeFlagName (
62     UINT32                  Flags);
63
64
65 /*******************************************************************************
66  *
67  * FUNCTION:    TrGetNextNode
68  *
69  * PARAMETERS:  None
70  *
71  * RETURN:      New parse node.  Aborts on allocation failure
72  *
73  * DESCRIPTION: Allocate a new parse node for the parse tree.  Bypass the local
74  *              dynamic memory manager for performance reasons (This has a
75  *              major impact on the speed of the compiler.)
76  *
77  ******************************************************************************/
78
79 static ACPI_PARSE_OBJECT *
80 TrGetNextNode (
81     void)
82 {
83
84     if (Gbl_NodeCacheNext >= Gbl_NodeCacheLast)
85     {
86         Gbl_NodeCacheNext = UtLocalCalloc (sizeof (ACPI_PARSE_OBJECT) *
87                                 ASL_NODE_CACHE_SIZE);
88         Gbl_NodeCacheLast = Gbl_NodeCacheNext + ASL_NODE_CACHE_SIZE;
89     }
90
91     return (Gbl_NodeCacheNext++);
92 }
93
94
95 /*******************************************************************************
96  *
97  * FUNCTION:    TrAllocateNode
98  *
99  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
100  *
101  * RETURN:      New parse node.  Aborts on allocation failure
102  *
103  * DESCRIPTION: Allocate and initialize a new parse node for the parse tree
104  *
105  ******************************************************************************/
106
107 ACPI_PARSE_OBJECT *
108 TrAllocateNode (
109     UINT32                  ParseOpcode)
110 {
111     ACPI_PARSE_OBJECT       *Op;
112
113
114     Op = TrGetNextNode ();
115
116     Op->Asl.ParseOpcode       = (UINT16) ParseOpcode;
117     Op->Asl.Filename          = Gbl_Files[ASL_FILE_INPUT].Filename;
118     Op->Asl.LineNumber        = Gbl_CurrentLineNumber;
119     Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber;
120     Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset;
121     Op->Asl.Column            = Gbl_CurrentColumn;
122
123     UtSetParseOpName (Op);
124     return Op;
125 }
126
127
128 /*******************************************************************************
129  *
130  * FUNCTION:    TrReleaseNode
131  *
132  * PARAMETERS:  Op            - Op to be released
133  *
134  * RETURN:      None
135  *
136  * DESCRIPTION: "release" a node.  In truth, nothing is done since the node
137  *              is part of a larger buffer
138  *
139  ******************************************************************************/
140
141 void
142 TrReleaseNode (
143     ACPI_PARSE_OBJECT       *Op)
144 {
145
146     return;
147 }
148
149
150 /*******************************************************************************
151  *
152  * FUNCTION:    TrUpdateNode
153  *
154  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
155  *              Op                - An existing parse node
156  *
157  * RETURN:      The updated node
158  *
159  * DESCRIPTION: Change the parse opcode assigned to a node.  Usually used to
160  *              change an opcode to DEFAULT_ARG so that the node is ignored
161  *              during the code generation.  Also used to set generic integers
162  *              to a specific size (8, 16, 32, or 64 bits)
163  *
164  ******************************************************************************/
165
166 ACPI_PARSE_OBJECT *
167 TrUpdateNode (
168     UINT32                  ParseOpcode,
169     ACPI_PARSE_OBJECT       *Op)
170 {
171
172     if (!Op)
173     {
174         return NULL;
175     }
176
177     DbgPrint (ASL_PARSE_OUTPUT,
178         "\nUpdateNode: Old - %s, New - %s\n\n",
179         UtGetOpName (Op->Asl.ParseOpcode),
180         UtGetOpName (ParseOpcode));
181
182     /* Assign new opcode and name */
183
184     if (Op->Asl.ParseOpcode == PARSEOP_ONES)
185     {
186         switch (ParseOpcode)
187         {
188         case PARSEOP_BYTECONST:
189             Op->Asl.Value.Integer = 0xFF;
190             break;
191
192         case PARSEOP_WORDCONST:
193             Op->Asl.Value.Integer = 0xFFFF;
194             break;
195
196         case PARSEOP_DWORDCONST:
197             Op->Asl.Value.Integer = 0xFFFFFFFF;
198             break;
199
200         default:
201             /* Don't care about others, don't need to check QWORD */
202             break;
203         }
204     }
205
206     Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
207     UtSetParseOpName (Op);
208
209     /*
210      * For the BYTE, WORD, and DWORD constants, make sure that the integer
211      * that was passed in will actually fit into the data type
212      */
213     switch (ParseOpcode)
214     {
215     case PARSEOP_BYTECONST:
216         Op = UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
217         break;
218
219     case PARSEOP_WORDCONST:
220         Op = UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
221         break;
222
223     case PARSEOP_DWORDCONST:
224         Op = UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
225         break;
226
227     default:
228         /* Don't care about others, don't need to check QWORD */
229         break;
230     }
231
232     return Op;
233 }
234
235
236 /*******************************************************************************
237  *
238  * FUNCTION:    TrGetNodeFlagName
239  *
240  * PARAMETERS:  Flags               - Flags word to be decoded
241  *
242  * RETURN:      Name string. Always returns a valid string pointer.
243  *
244  * DESCRIPTION: Decode a flags word
245  *
246  ******************************************************************************/
247
248 static char *
249 TrGetNodeFlagName (
250     UINT32                  Flags)
251 {
252
253     switch (Flags)
254     {
255     case NODE_VISITED:
256         return ("NODE_VISITED");
257
258     case NODE_AML_PACKAGE:
259         return ("NODE_AML_PACKAGE");
260
261     case NODE_IS_TARGET:
262         return ("NODE_IS_TARGET");
263
264     case NODE_IS_RESOURCE_DESC:
265         return ("NODE_IS_RESOURCE_DESC");
266
267     case NODE_IS_RESOURCE_FIELD:
268         return ("NODE_IS_RESOURCE_FIELD");
269
270     case NODE_HAS_NO_EXIT:
271         return ("NODE_HAS_NO_EXIT");
272
273     case NODE_IF_HAS_NO_EXIT:
274         return ("NODE_IF_HAS_NO_EXIT");
275
276     case NODE_NAME_INTERNALIZED:
277         return ("NODE_NAME_INTERNALIZED");
278
279     case NODE_METHOD_NO_RETVAL:
280         return ("NODE_METHOD_NO_RETVAL");
281
282     case NODE_METHOD_SOME_NO_RETVAL:
283         return ("NODE_METHOD_SOME_NO_RETVAL");
284
285     case NODE_RESULT_NOT_USED:
286         return ("NODE_RESULT_NOT_USED");
287
288     case NODE_METHOD_TYPED:
289         return ("NODE_METHOD_TYPED");
290
291     case NODE_COMPILE_TIME_CONST:
292         return ("NODE_COMPILE_TIME_CONST");
293
294     case NODE_IS_TERM_ARG:
295         return ("NODE_IS_TERM_ARG");
296
297     case NODE_WAS_ONES_OP:
298         return ("NODE_WAS_ONES_OP");
299
300     case NODE_IS_NAME_DECLARATION:
301         return ("NODE_IS_NAME_DECLARATION");
302
303     default:
304         return ("Multiple Flags (or unknown flag) set");
305     }
306 }
307
308
309 /*******************************************************************************
310  *
311  * FUNCTION:    TrSetNodeFlags
312  *
313  * PARAMETERS:  Op                  - An existing parse node
314  *              Flags               - New flags word
315  *
316  * RETURN:      The updated parser op
317  *
318  * DESCRIPTION: Set bits in the node flags word.  Will not clear bits, only set
319  *
320  ******************************************************************************/
321
322 ACPI_PARSE_OBJECT *
323 TrSetNodeFlags (
324     ACPI_PARSE_OBJECT       *Op,
325     UINT32                  Flags)
326 {
327
328     DbgPrint (ASL_PARSE_OUTPUT,
329         "\nSetNodeFlags: Op %p, %8.8X %s\n\n", Op, Flags,
330         TrGetNodeFlagName (Flags));
331
332     if (!Op)
333     {
334         return NULL;
335     }
336
337     Op->Asl.CompileFlags |= Flags;
338
339     return Op;
340 }
341
342
343 /*******************************************************************************
344  *
345  * FUNCTION:    TrSetEndLineNumber
346  *
347  * PARAMETERS:  Op                - An existing parse node
348  *
349  * RETURN:      None.
350  *
351  * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
352  *              parse node to the current line numbers.
353  *
354  ******************************************************************************/
355
356 void
357 TrSetEndLineNumber (
358     ACPI_PARSE_OBJECT       *Op)
359 {
360
361     /* If the end line # is already set, just return */
362
363     if (Op->Asl.EndLine)
364     {
365         return;
366     }
367
368     Op->Asl.EndLine        = Gbl_CurrentLineNumber;
369     Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber;
370 }
371
372
373 /*******************************************************************************
374  *
375  * FUNCTION:    TrCreateLeafNode
376  *
377  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
378  *
379  * RETURN:      Pointer to the new node.  Aborts on allocation failure
380  *
381  * DESCRIPTION: Create a simple leaf node (no children or peers, and no value
382  *              assigned to the node)
383  *
384  ******************************************************************************/
385
386 ACPI_PARSE_OBJECT *
387 TrCreateLeafNode (
388     UINT32                  ParseOpcode)
389 {
390     ACPI_PARSE_OBJECT       *Op;
391
392
393     Op = TrAllocateNode (ParseOpcode);
394
395     DbgPrint (ASL_PARSE_OUTPUT,
396         "\nCreateLeafNode  Ln/Col %u/%u NewNode %p  Op %s\n\n",
397         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode));
398
399     return Op;
400 }
401
402
403 /*******************************************************************************
404  *
405  * FUNCTION:    TrCreateConstantLeafNode
406  *
407  * PARAMETERS:  ParseOpcode         - The constant opcode
408  *
409  * RETURN:      Pointer to the new node.  Aborts on allocation failure
410  *
411  * DESCRIPTION: Create a leaf node (no children or peers) for one of the
412  *              special constants - __LINE__, __FILE__, and __DATE__.
413  *
414  * Note: An implemenation of __FUNC__ cannot happen here because we don't
415  * have a full parse tree at this time and cannot find the parent control
416  * method. If it is ever needed, __FUNC__ must be implemented later, after
417  * the parse tree has been fully constructed.
418  *
419  ******************************************************************************/
420
421 ACPI_PARSE_OBJECT *
422 TrCreateConstantLeafNode (
423     UINT32                  ParseOpcode)
424 {
425     ACPI_PARSE_OBJECT       *Op = NULL;
426     time_t                  CurrentTime;
427     char                    *StaticTimeString;
428     char                    *TimeString;
429     char                    *Path;
430     char                    *Filename;
431
432
433     switch (ParseOpcode)
434     {
435     case PARSEOP___LINE__:
436         Op = TrAllocateNode (PARSEOP_INTEGER);
437         Op->Asl.Value.Integer = Op->Asl.LineNumber;
438         break;
439
440     case PARSEOP___PATH__:
441         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
442
443         /* Op.Asl.Filename contains the full pathname to the file */
444
445         Op->Asl.Value.String = Op->Asl.Filename;
446         break;
447
448     case PARSEOP___FILE__:
449         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
450
451         /* Get the simple filename from the full path */
452
453         FlSplitInputPathname (Op->Asl.Filename, &Path, &Filename);
454         ACPI_FREE (Path);
455         Op->Asl.Value.String = Filename;
456         break;
457
458     case PARSEOP___DATE__:
459         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
460
461         /* Get a copy of the current time */
462
463         CurrentTime = time (NULL);
464         StaticTimeString = ctime (&CurrentTime);
465         TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1);
466         strcpy (TimeString, StaticTimeString);
467
468         TimeString[strlen(TimeString) -1] = 0;  /* Remove trailing newline */
469         Op->Asl.Value.String = TimeString;
470         break;
471
472     default: /* This would be an internal error */
473         return (NULL);
474     }
475
476     DbgPrint (ASL_PARSE_OUTPUT,
477         "\nCreateConstantLeafNode  Ln/Col %u/%u NewNode %p  Op %s  Value %8.8X%8.8X  ",
478         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode),
479         ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
480     return (Op);
481 }
482
483
484 /*******************************************************************************
485  *
486  * FUNCTION:    TrCreateValuedLeafNode
487  *
488  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
489  *              Value               - Value to be assigned to the node
490  *
491  * RETURN:      Pointer to the new node.  Aborts on allocation failure
492  *
493  * DESCRIPTION: Create a leaf node (no children or peers) with a value
494  *              assigned to it
495  *
496  ******************************************************************************/
497
498 ACPI_PARSE_OBJECT *
499 TrCreateValuedLeafNode (
500     UINT32                  ParseOpcode,
501     UINT64                  Value)
502 {
503     ACPI_PARSE_OBJECT       *Op;
504
505
506     Op = TrAllocateNode (ParseOpcode);
507
508     DbgPrint (ASL_PARSE_OUTPUT,
509         "\nCreateValuedLeafNode  Ln/Col %u/%u NewNode %p  Op %s  Value %8.8X%8.8X  ",
510         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode),
511         ACPI_FORMAT_UINT64 (Value));
512     Op->Asl.Value.Integer = Value;
513
514     switch (ParseOpcode)
515     {
516     case PARSEOP_STRING_LITERAL:
517         DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value);
518         break;
519
520     case PARSEOP_NAMESEG:
521         DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value);
522         break;
523
524     case PARSEOP_NAMESTRING:
525         DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value);
526         break;
527
528     case PARSEOP_EISAID:
529         DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value);
530         break;
531
532     case PARSEOP_METHOD:
533         DbgPrint (ASL_PARSE_OUTPUT, "METHOD");
534         break;
535
536     case PARSEOP_INTEGER:
537         DbgPrint (ASL_PARSE_OUTPUT, "INTEGER");
538         break;
539
540     default:
541         break;
542     }
543
544     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
545     return Op;
546 }
547
548
549 /*******************************************************************************
550  *
551  * FUNCTION:    TrCreateNode
552  *
553  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
554  *              NumChildren         - Number of children to follow
555  *              ...                 - A list of child nodes to link to the new
556  *                                    node.  NumChildren long.
557  *
558  * RETURN:      Pointer to the new node.  Aborts on allocation failure
559  *
560  * DESCRIPTION: Create a new parse node and link together a list of child
561  *              nodes underneath the new node.
562  *
563  ******************************************************************************/
564
565 ACPI_PARSE_OBJECT *
566 TrCreateNode (
567     UINT32                  ParseOpcode,
568     UINT32                  NumChildren,
569     ...)
570 {
571     ACPI_PARSE_OBJECT       *Op;
572     ACPI_PARSE_OBJECT       *Child;
573     ACPI_PARSE_OBJECT       *PrevChild;
574     va_list                 ap;
575     UINT32                  i;
576     BOOLEAN                 FirstChild;
577
578
579     va_start (ap, NumChildren);
580
581     /* Allocate one new node */
582
583     Op = TrAllocateNode (ParseOpcode);
584
585     DbgPrint (ASL_PARSE_OUTPUT,
586         "\nCreateNode  Ln/Col %u/%u NewParent %p Child %u Op %s  ",
587         Op->Asl.LineNumber, Op->Asl.Column, Op, NumChildren, UtGetOpName(ParseOpcode));
588
589     /* Some extra debug output based on the parse opcode */
590
591     switch (ParseOpcode)
592     {
593     case PARSEOP_DEFINITIONBLOCK:
594         RootNode = Op;
595         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
596         break;
597
598     case PARSEOP_OPERATIONREGION:
599         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
600         break;
601
602     case PARSEOP_OR:
603         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
604         break;
605
606     default:
607         /* Nothing to do for other opcodes */
608         break;
609     }
610
611     /* Link the new node to its children */
612
613     PrevChild = NULL;
614     FirstChild = TRUE;
615     for (i = 0; i < NumChildren; i++)
616     {
617         /* Get the next child */
618
619         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
620         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
621
622         /*
623          * If child is NULL, this means that an optional argument
624          * was omitted.  We must create a placeholder with a special
625          * opcode (DEFAULT_ARG) so that the code generator will know
626          * that it must emit the correct default for this argument
627          */
628         if (!Child)
629         {
630             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
631         }
632
633         /* Link first child to parent */
634
635         if (FirstChild)
636         {
637             FirstChild = FALSE;
638             Op->Asl.Child = Child;
639         }
640
641         /* Point all children to parent */
642
643         Child->Asl.Parent = Op;
644
645         /* Link children in a peer list */
646
647         if (PrevChild)
648         {
649             PrevChild->Asl.Next = Child;
650         };
651
652         /*
653          * This child might be a list, point all nodes in the list
654          * to the same parent
655          */
656         while (Child->Asl.Next)
657         {
658             Child = Child->Asl.Next;
659             Child->Asl.Parent = Op;
660         }
661
662         PrevChild = Child;
663     }
664     va_end(ap);
665
666     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
667     return Op;
668 }
669
670
671 /*******************************************************************************
672  *
673  * FUNCTION:    TrLinkChildren
674  *
675  * PARAMETERS:  Op                - An existing parse node
676  *              NumChildren         - Number of children to follow
677  *              ...                 - A list of child nodes to link to the new
678  *                                    node.  NumChildren long.
679  *
680  * RETURN:      The updated (linked) node
681  *
682  * DESCRIPTION: Link a group of nodes to an existing parse node
683  *
684  ******************************************************************************/
685
686 ACPI_PARSE_OBJECT *
687 TrLinkChildren (
688     ACPI_PARSE_OBJECT       *Op,
689     UINT32                  NumChildren,
690     ...)
691 {
692     ACPI_PARSE_OBJECT       *Child;
693     ACPI_PARSE_OBJECT       *PrevChild;
694     va_list                 ap;
695     UINT32                  i;
696     BOOLEAN                 FirstChild;
697
698
699     va_start (ap, NumChildren);
700
701
702     TrSetEndLineNumber (Op);
703
704     DbgPrint (ASL_PARSE_OUTPUT,
705         "\nLinkChildren  Line [%u to %u] NewParent %p Child %u Op %s  ",
706         Op->Asl.LineNumber, Op->Asl.EndLine,
707         Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
708
709     switch (Op->Asl.ParseOpcode)
710     {
711     case PARSEOP_DEFINITIONBLOCK:
712         RootNode = Op;
713         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
714         break;
715
716     case PARSEOP_OPERATIONREGION:
717         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
718         break;
719
720     case PARSEOP_OR:
721         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
722         break;
723
724     default:
725         /* Nothing to do for other opcodes */
726         break;
727     }
728
729     /* Link the new node to it's children */
730
731     PrevChild = NULL;
732     FirstChild = TRUE;
733     for (i = 0; i < NumChildren; i++)
734     {
735         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
736
737         if ((Child == PrevChild) && (Child != NULL))
738         {
739             AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
740                 "Child node list invalid");
741             return Op;
742         }
743
744         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
745
746         /*
747          * If child is NULL, this means that an optional argument
748          * was omitted.  We must create a placeholder with a special
749          * opcode (DEFAULT_ARG) so that the code generator will know
750          * that it must emit the correct default for this argument
751          */
752         if (!Child)
753         {
754             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
755         }
756
757         /* Link first child to parent */
758
759         if (FirstChild)
760         {
761             FirstChild = FALSE;
762             Op->Asl.Child = Child;
763         }
764
765         /* Point all children to parent */
766
767         Child->Asl.Parent = Op;
768
769         /* Link children in a peer list */
770
771         if (PrevChild)
772         {
773             PrevChild->Asl.Next = Child;
774         };
775
776         /*
777          * This child might be a list, point all nodes in the list
778          * to the same parent
779          */
780         while (Child->Asl.Next)
781         {
782             Child = Child->Asl.Next;
783             Child->Asl.Parent = Op;
784         }
785         PrevChild = Child;
786     }
787     va_end(ap);
788
789     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
790     return Op;
791 }
792
793
794 /*******************************************************************************
795  *
796  * FUNCTION:    TrLinkPeerNode
797  *
798  * PARAMETERS:  Op1           - First peer
799  *              Op2           - Second peer
800  *
801  * RETURN:      Op1 or the non-null node.
802  *
803  * DESCRIPTION: Link two nodes as peers.  Handles cases where one peer is null.
804  *
805  ******************************************************************************/
806
807 ACPI_PARSE_OBJECT *
808 TrLinkPeerNode (
809     ACPI_PARSE_OBJECT       *Op1,
810     ACPI_PARSE_OBJECT       *Op2)
811 {
812     ACPI_PARSE_OBJECT       *Next;
813
814
815     DbgPrint (ASL_PARSE_OUTPUT,
816         "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n\n",
817         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
818         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
819
820
821     if ((!Op1) && (!Op2))
822     {
823         DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n");
824         return Op1;
825     }
826
827     /* If one of the nodes is null, just return the non-null node */
828
829     if (!Op2)
830     {
831         return Op1;
832     }
833
834     if (!Op1)
835     {
836         return Op2;
837     }
838
839     if (Op1 == Op2)
840     {
841         DbgPrint (ASL_DEBUG_OUTPUT,
842             "\n\n************* Internal error, linking node to itself %p\n\n\n",
843             Op1);
844         AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
845             "Linking node to itself");
846         return Op1;
847     }
848
849     Op1->Asl.Parent = Op2->Asl.Parent;
850
851     /*
852      * Op 1 may already have a peer list (such as an IF/ELSE pair),
853      * so we must walk to the end of the list and attach the new
854      * peer at the end
855      */
856     Next = Op1;
857     while (Next->Asl.Next)
858     {
859         Next = Next->Asl.Next;
860     }
861
862     Next->Asl.Next = Op2;
863     return Op1;
864 }
865
866
867 /*******************************************************************************
868  *
869  * FUNCTION:    TrLinkPeerNodes
870  *
871  * PARAMETERS:  NumPeers            - The number of nodes in the list to follow
872  *              ...                 - A list of nodes to link together as peers
873  *
874  * RETURN:      The first node in the list (head of the peer list)
875  *
876  * DESCRIPTION: Link together an arbitrary number of peer nodes.
877  *
878  ******************************************************************************/
879
880 ACPI_PARSE_OBJECT *
881 TrLinkPeerNodes (
882     UINT32                  NumPeers,
883     ...)
884 {
885     ACPI_PARSE_OBJECT       *This;
886     ACPI_PARSE_OBJECT       *Next;
887     va_list                 ap;
888     UINT32                  i;
889     ACPI_PARSE_OBJECT       *Start;
890
891
892     DbgPrint (ASL_PARSE_OUTPUT,
893         "\nLinkPeerNodes: (%u) ", NumPeers);
894
895     va_start (ap, NumPeers);
896     This = va_arg (ap, ACPI_PARSE_OBJECT *);
897     Start = This;
898
899     /*
900      * Link all peers
901      */
902     for (i = 0; i < (NumPeers -1); i++)
903     {
904         DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
905
906         while (This->Asl.Next)
907         {
908             This = This->Asl.Next;
909         }
910
911         /* Get another peer node */
912
913         Next = va_arg (ap, ACPI_PARSE_OBJECT *);
914         if (!Next)
915         {
916             Next = TrAllocateNode (PARSEOP_DEFAULT_ARG);
917         }
918
919         /* link new node to the current node */
920
921         This->Asl.Next = Next;
922         This = Next;
923     }
924     va_end (ap);
925
926     DbgPrint (ASL_PARSE_OUTPUT,"\n\n");
927     return (Start);
928 }
929
930
931 /*******************************************************************************
932  *
933  * FUNCTION:    TrLinkChildNode
934  *
935  * PARAMETERS:  Op1           - Parent node
936  *              Op2           - Op to become a child
937  *
938  * RETURN:      The parent node
939  *
940  * DESCRIPTION: Link two nodes together as a parent and child
941  *
942  ******************************************************************************/
943
944 ACPI_PARSE_OBJECT *
945 TrLinkChildNode (
946     ACPI_PARSE_OBJECT       *Op1,
947     ACPI_PARSE_OBJECT       *Op2)
948 {
949     ACPI_PARSE_OBJECT       *Next;
950
951
952     DbgPrint (ASL_PARSE_OUTPUT,
953         "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n\n",
954         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
955         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
956
957     if (!Op1 || !Op2)
958     {
959         return Op1;
960     }
961
962     Op1->Asl.Child = Op2;
963
964     /* Set the child and all peers of the child to point to the parent */
965
966     Next = Op2;
967     while (Next)
968     {
969         Next->Asl.Parent = Op1;
970         Next = Next->Asl.Next;
971     }
972
973     return Op1;
974 }
975
976
977 /*******************************************************************************
978  *
979  * FUNCTION:    TrWalkParseTree
980  *
981  * PARAMETERS:  Visitation              - Type of walk
982  *              DescendingCallback      - Called during tree descent
983  *              AscendingCallback       - Called during tree ascent
984  *              Context                 - To be passed to the callbacks
985  *
986  * RETURN:      Status from callback(s)
987  *
988  * DESCRIPTION: Walk the entire parse tree.
989  *
990  ******************************************************************************/
991
992 ACPI_STATUS
993 TrWalkParseTree (
994     ACPI_PARSE_OBJECT       *Op,
995     UINT32                  Visitation,
996     ASL_WALK_CALLBACK       DescendingCallback,
997     ASL_WALK_CALLBACK       AscendingCallback,
998     void                    *Context)
999 {
1000     UINT32                  Level;
1001     BOOLEAN                 NodePreviouslyVisited;
1002     ACPI_PARSE_OBJECT       *StartOp = Op;
1003     ACPI_STATUS             Status;
1004
1005
1006     if (!RootNode)
1007     {
1008         return (AE_OK);
1009     }
1010
1011     Level = 0;
1012     NodePreviouslyVisited = FALSE;
1013
1014     switch (Visitation)
1015     {
1016     case ASL_WALK_VISIT_DOWNWARD:
1017
1018         while (Op)
1019         {
1020             if (!NodePreviouslyVisited)
1021             {
1022                 /* Let the callback process the node. */
1023
1024                 Status = DescendingCallback (Op, Level, Context);
1025                 if (ACPI_SUCCESS (Status))
1026                 {
1027                     /* Visit children first, once */
1028
1029                     if (Op->Asl.Child)
1030                     {
1031                         Level++;
1032                         Op = Op->Asl.Child;
1033                         continue;
1034                     }
1035                 }
1036                 else if (Status != AE_CTRL_DEPTH)
1037                 {
1038                     /* Exit immediately on any error */
1039
1040                     return (Status);
1041                 }
1042             }
1043
1044             /* Terminate walk at start op */
1045
1046             if (Op == StartOp)
1047             {
1048                 break;
1049             }
1050
1051             /* No more children, visit peers */
1052
1053             if (Op->Asl.Next)
1054             {
1055                 Op = Op->Asl.Next;
1056                 NodePreviouslyVisited = FALSE;
1057             }
1058             else
1059             {
1060                 /* No children or peers, re-visit parent */
1061
1062                 if (Level != 0 )
1063                 {
1064                     Level--;
1065                 }
1066                 Op = Op->Asl.Parent;
1067                 NodePreviouslyVisited = TRUE;
1068             }
1069         }
1070         break;
1071
1072
1073     case ASL_WALK_VISIT_UPWARD:
1074
1075         while (Op)
1076         {
1077             /* Visit leaf node (no children) or parent node on return trip */
1078
1079             if ((!Op->Asl.Child) ||
1080                 (NodePreviouslyVisited))
1081             {
1082                 /* Let the callback process the node. */
1083
1084                 Status = AscendingCallback (Op, Level, Context);
1085                 if (ACPI_FAILURE (Status))
1086                 {
1087                     return (Status);
1088                 }
1089             }
1090             else
1091             {
1092                 /* Visit children first, once */
1093
1094                 Level++;
1095                 Op = Op->Asl.Child;
1096                 continue;
1097             }
1098
1099             /* Terminate walk at start op */
1100
1101             if (Op == StartOp)
1102             {
1103                 break;
1104             }
1105
1106             /* No more children, visit peers */
1107
1108             if (Op->Asl.Next)
1109             {
1110                 Op = Op->Asl.Next;
1111                 NodePreviouslyVisited = FALSE;
1112             }
1113             else
1114             {
1115                 /* No children or peers, re-visit parent */
1116
1117                 if (Level != 0 )
1118                 {
1119                     Level--;
1120                 }
1121                 Op = Op->Asl.Parent;
1122                 NodePreviouslyVisited = TRUE;
1123             }
1124         }
1125         break;
1126
1127
1128      case ASL_WALK_VISIT_TWICE:
1129
1130         while (Op)
1131         {
1132             if (NodePreviouslyVisited)
1133             {
1134                 Status = AscendingCallback (Op, Level, Context);
1135                 if (ACPI_FAILURE (Status))
1136                 {
1137                     return (Status);
1138                 }
1139             }
1140             else
1141             {
1142                 /* Let the callback process the node. */
1143
1144                 Status = DescendingCallback (Op, Level, Context);
1145                 if (ACPI_SUCCESS (Status))
1146                 {
1147                     /* Visit children first, once */
1148
1149                     if (Op->Asl.Child)
1150                     {
1151                         Level++;
1152                         Op = Op->Asl.Child;
1153                         continue;
1154                     }
1155                 }
1156                 else if (Status != AE_CTRL_DEPTH)
1157                 {
1158                     /* Exit immediately on any error */
1159
1160                     return (Status);
1161                 }
1162             }
1163
1164             /* Terminate walk at start op */
1165
1166             if (Op == StartOp)
1167             {
1168                 break;
1169             }
1170
1171             /* No more children, visit peers */
1172
1173             if (Op->Asl.Next)
1174             {
1175                 Op = Op->Asl.Next;
1176                 NodePreviouslyVisited = FALSE;
1177             }
1178             else
1179             {
1180                 /* No children or peers, re-visit parent */
1181
1182                 if (Level != 0 )
1183                 {
1184                     Level--;
1185                 }
1186                 Op = Op->Asl.Parent;
1187                 NodePreviouslyVisited = TRUE;
1188             }
1189         }
1190         break;
1191
1192     default:
1193         /* No other types supported */
1194         break;
1195     }
1196
1197     /* If we get here, the walk completed with no errors */
1198
1199     return (AE_OK);
1200 }
1201
1202