asltree.c revision 1.9 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