xref: /freebsd/sys/contrib/dev/acpica/compiler/prscan.c (revision 57718be8fa0bd5edc11ab9a72e68cc71982939a6)
1 /******************************************************************************
2  *
3  * Module Name: prscan - Preprocessor start-up and file scan module
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, 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 #define _DECLARE_PR_GLOBALS
45 
46 #include <contrib/dev/acpica/compiler/aslcompiler.h>
47 #include <contrib/dev/acpica/compiler/dtcompiler.h>
48 
49 /*
50  * TBDs:
51  *
52  * No nested macros, maybe never
53  * Implement ASL "Include" as well as "#include" here?
54  */
55 #define _COMPONENT          ASL_PREPROCESSOR
56         ACPI_MODULE_NAME    ("prscan")
57 
58 
59 /* Local prototypes */
60 
61 static void
62 PrPreprocessInputFile (
63     void);
64 
65 static void
66 PrDoDirective (
67     char                    *DirectiveToken,
68     char                    **Next);
69 
70 static int
71 PrMatchDirective (
72     char                    *Directive);
73 
74 static void
75 PrPushDirective (
76     int                     Directive,
77     char                    *Argument);
78 
79 static ACPI_STATUS
80 PrPopDirective (
81     void);
82 
83 static void
84 PrDbgPrint (
85     char                    *Action,
86     char                    *DirectiveName);
87 
88 
89 /*
90  * Supported preprocessor directives
91  */
92 static const PR_DIRECTIVE_INFO      Gbl_DirectiveInfo[] =
93 {
94     {"define",  1},
95     {"elif",    0}, /* Converted to #else..#if internally */
96     {"else",    0},
97     {"endif",   0},
98     {"error",   1},
99     {"if",      1},
100     {"ifdef",   1},
101     {"ifndef",  1},
102     {"include", 0}, /* Argument is not standard format, so 0 */
103     {"line",    1},
104     {"pragma",  1},
105     {"undef",   1},
106     {"warning", 1},
107     {NULL,      0}
108 };
109 
110 enum Gbl_DirectiveIndexes
111 {
112     PR_DIRECTIVE_DEFINE = 0,
113     PR_DIRECTIVE_ELIF,
114     PR_DIRECTIVE_ELSE,
115     PR_DIRECTIVE_ENDIF,
116     PR_DIRECTIVE_ERROR,
117     PR_DIRECTIVE_IF,
118     PR_DIRECTIVE_IFDEF,
119     PR_DIRECTIVE_IFNDEF,
120     PR_DIRECTIVE_INCLUDE,
121     PR_DIRECTIVE_LINE,
122     PR_DIRECTIVE_PRAGMA,
123     PR_DIRECTIVE_UNDEF,
124     PR_DIRECTIVE_WARNING,
125 };
126 
127 #define ASL_DIRECTIVE_NOT_FOUND     -1
128 
129 
130 /*******************************************************************************
131  *
132  * FUNCTION:    PrInitializePreprocessor
133  *
134  * PARAMETERS:  None
135  *
136  * RETURN:      None
137  *
138  * DESCRIPTION: Startup initialization for the Preprocessor.
139  *
140  ******************************************************************************/
141 
142 void
143 PrInitializePreprocessor (
144     void)
145 {
146     /* Init globals and the list of #defines */
147 
148     PrInitializeGlobals ();
149     Gbl_DefineList = NULL;
150 }
151 
152 
153 /*******************************************************************************
154  *
155  * FUNCTION:    PrInitializeGlobals
156  *
157  * PARAMETERS:  None
158  *
159  * RETURN:      None
160  *
161  * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup
162  *              initialization and re-initialization between compiles during
163  *              a multiple source file compile.
164  *
165  ******************************************************************************/
166 
167 void
168 PrInitializeGlobals (
169     void)
170 {
171     /* Init globals */
172 
173     Gbl_InputFileList = NULL;
174     Gbl_CurrentLineNumber = 0;
175     Gbl_PreprocessorLineNumber = 1;
176     Gbl_PreprocessorError = FALSE;
177 
178     /* These are used to track #if/#else blocks (possibly nested) */
179 
180     Gbl_IfDepth = 0;
181     Gbl_IgnoringThisCodeBlock = FALSE;
182     Gbl_DirectiveStack = NULL;
183 }
184 
185 
186 /*******************************************************************************
187  *
188  * FUNCTION:    PrTerminatePreprocessor
189  *
190  * PARAMETERS:  None
191  *
192  * RETURN:      None
193  *
194  * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any
195  *              defines that were specified on the command line, in order to
196  *              support multiple compiles with a single compiler invocation.
197  *
198  ******************************************************************************/
199 
200 void
201 PrTerminatePreprocessor (
202     void)
203 {
204     PR_DEFINE_INFO          *DefineInfo;
205 
206 
207     /*
208      * The persistent defines (created on the command line) are always at the
209      * end of the list. We save them.
210      */
211     while ((Gbl_DefineList) && (!Gbl_DefineList->Persist))
212     {
213         DefineInfo = Gbl_DefineList;
214         Gbl_DefineList = DefineInfo->Next;
215 
216         ACPI_FREE (DefineInfo->Replacement);
217         ACPI_FREE (DefineInfo->Identifier);
218         ACPI_FREE (DefineInfo);
219     }
220 }
221 
222 
223 /*******************************************************************************
224  *
225  * FUNCTION:    PrDoPreprocess
226  *
227  * PARAMETERS:  None
228  *
229  * RETURN:      None
230  *
231  * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must
232  *              be already open. Handles multiple input files via the
233  *              #include directive.
234  *
235  ******************************************************************************/
236 
237 void
238 PrDoPreprocess (
239     void)
240 {
241     BOOLEAN                 MoreInputFiles;
242 
243 
244     DbgPrint (ASL_DEBUG_OUTPUT, "Starting preprocessing phase\n\n");
245 
246 
247     FlSeekFile (ASL_FILE_INPUT, 0);
248     PrDumpPredefinedNames ();
249 
250     /* Main preprocessor loop, handles include files */
251 
252     do
253     {
254         PrPreprocessInputFile ();
255         MoreInputFiles = PrPopInputFileStack ();
256 
257     } while (MoreInputFiles);
258 
259     /* Point compiler input to the new preprocessor output file (.i) */
260 
261     FlCloseFile (ASL_FILE_INPUT);
262     Gbl_Files[ASL_FILE_INPUT].Handle = Gbl_Files[ASL_FILE_PREPROCESSOR].Handle;
263     AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle;
264 
265     /* Reset globals to allow compiler to run */
266 
267     FlSeekFile (ASL_FILE_INPUT, 0);
268     Gbl_CurrentLineNumber = 1;
269 
270     DbgPrint (ASL_DEBUG_OUTPUT, "Preprocessing phase complete \n\n");
271 }
272 
273 
274 /*******************************************************************************
275  *
276  * FUNCTION:    PrPreprocessInputFile
277  *
278  * PARAMETERS:  None
279  *
280  * RETURN:      None
281  *
282  * DESCRIPTION: Preprocess one entire file, line-by-line.
283  *
284  * Input:  Raw user ASL from ASL_FILE_INPUT
285  * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR
286  *
287  ******************************************************************************/
288 
289 static void
290 PrPreprocessInputFile (
291     void)
292 {
293     UINT32                  Offset;
294     char                    *Token;
295     char                    *ReplaceString;
296     PR_DEFINE_INFO          *DefineInfo;
297     ACPI_SIZE               TokenOffset;
298     char                    *Next;
299     int                     OffsetAdjust;
300 
301 
302     /* Scan line-by-line. Comments and blank lines are skipped by this function */
303 
304     while ((Offset = DtGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF)
305     {
306         /* Need a copy of the input line for strok() */
307 
308         strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
309         Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
310         OffsetAdjust = 0;
311 
312         /* All preprocessor directives must begin with '#' */
313 
314         if (Token && (*Token == '#'))
315         {
316             if (strlen (Token) == 1)
317             {
318                 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
319             }
320             else
321             {
322                 Token++;    /* Skip leading # */
323             }
324 
325             /* Execute the directive, do not write line to output file */
326 
327             PrDoDirective (Token, &Next);
328             continue;
329         }
330 
331         /*
332          * If we are currently within the part of an IF/ELSE block that is
333          * FALSE, ignore the line and do not write it to the output file.
334          * This continues until an #else or #endif is encountered.
335          */
336         if (Gbl_IgnoringThisCodeBlock)
337         {
338             continue;
339         }
340 
341         /* Match and replace all #defined names within this source line */
342 
343         while (Token)
344         {
345             DefineInfo = PrMatchDefine (Token);
346             if (DefineInfo)
347             {
348                 if (DefineInfo->Body)
349                 {
350                     /* This is a macro */
351 
352                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
353                         "Matched Macro: %s->%s\n",
354                         Gbl_CurrentLineNumber, DefineInfo->Identifier,
355                         DefineInfo->Replacement);
356 
357                     PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
358                         DefineInfo, &Next);
359                 }
360                 else
361                 {
362                     ReplaceString = DefineInfo->Replacement;
363 
364                     /* Replace the name in the original line buffer */
365 
366                     TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
367                     PrReplaceData (
368                         &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
369                         ReplaceString, strlen (ReplaceString));
370 
371                     /* Adjust for length difference between old and new name length */
372 
373                     OffsetAdjust += strlen (ReplaceString) - strlen (Token);
374 
375                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
376                         "Matched #define: %s->%s\n",
377                         Gbl_CurrentLineNumber, Token,
378                         *ReplaceString ? ReplaceString : "(NULL STRING)");
379                 }
380             }
381 
382             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
383         }
384 
385 #if 0
386 /* Line prefix */
387         FlPrintFile (ASL_FILE_PREPROCESSOR, "/* %14s  %.5u  i:%.5u */ ",
388             Gbl_Files[ASL_FILE_INPUT].Filename,
389             Gbl_CurrentLineNumber, Gbl_PreprocessorLineNumber);
390 #endif
391 
392         /*
393          * Emit a #line directive if necessary, to keep the line numbers in
394          * the (.i) file synchronized with the original source code file, so
395          * that the correct line number appears in any error messages
396          * generated by the actual compiler.
397          */
398         if (Gbl_CurrentLineNumber > (Gbl_PreviousLineNumber + 1))
399         {
400             FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u\n",
401                 Gbl_CurrentLineNumber);
402         }
403 
404         Gbl_PreviousLineNumber = Gbl_CurrentLineNumber;
405         Gbl_PreprocessorLineNumber++;
406 
407         /*
408          * Now we can write the possibly modified source line to the
409          * preprocessor (.i) file
410          */
411         FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
412             strlen (Gbl_CurrentLineBuffer));
413     }
414 }
415 
416 
417 /*******************************************************************************
418  *
419  * FUNCTION:    PrDoDirective
420  *
421  * PARAMETERS:  Directive               - Pointer to directive name token
422  *              Next                    - "Next" buffer from GetNextToken
423  *
424  * RETURN:      None.
425  *
426  * DESCRIPTION: Main processing for all preprocessor directives
427  *
428  ******************************************************************************/
429 
430 static void
431 PrDoDirective (
432     char                    *DirectiveToken,
433     char                    **Next)
434 {
435     char                    *Token = Gbl_MainTokenBuffer;
436     char                    *Token2;
437     char                    *End;
438     UINT64                  Value;
439     ACPI_SIZE               TokenOffset;
440     int                     Directive;
441     ACPI_STATUS             Status;
442 
443 
444     if (!DirectiveToken)
445     {
446         goto SyntaxError;
447     }
448 
449     Directive = PrMatchDirective (DirectiveToken);
450     if (Directive == ASL_DIRECTIVE_NOT_FOUND)
451     {
452         PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
453             THIS_TOKEN_OFFSET (DirectiveToken));
454 
455         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
456             "#%s: Unknown directive\n",
457             Gbl_CurrentLineNumber, DirectiveToken);
458         return;
459     }
460 
461     /*
462      * If we are currently ignoring this block and we encounter a #else or
463      * #elif, we must ignore their blocks also if the parent block is also
464      * being ignored.
465      */
466     if (Gbl_IgnoringThisCodeBlock)
467     {
468         switch (Directive)
469         {
470         case PR_DIRECTIVE_ELSE:
471         case PR_DIRECTIVE_ELIF:
472 
473             if (Gbl_DirectiveStack && Gbl_DirectiveStack->IgnoringThisCodeBlock)
474             {
475                 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
476                 return;
477             }
478             break;
479 
480         default:
481             break;
482         }
483     }
484 
485     /*
486      * Need to always check for #else, #elif, #endif regardless of
487      * whether we are ignoring the current code block, since these
488      * are conditional code block terminators.
489      */
490     switch (Directive)
491     {
492     case PR_DIRECTIVE_ELSE:
493 
494         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
495         PrDbgPrint ("Executing", "else block");
496         return;
497 
498     case PR_DIRECTIVE_ELIF:
499 
500         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
501         Directive = PR_DIRECTIVE_IF;
502 
503         if (Gbl_IgnoringThisCodeBlock == TRUE)
504         {
505             /* Not executing the ELSE part -- all done here */
506             PrDbgPrint ("Ignoring", "elif block");
507             return;
508         }
509 
510         /*
511          * After this, we will execute the IF part further below.
512          * First, however, pop off the original #if directive.
513          */
514         if (ACPI_FAILURE (PrPopDirective ()))
515         {
516             PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
517                 THIS_TOKEN_OFFSET (DirectiveToken));
518         }
519 
520         PrDbgPrint ("Executing", "elif block");
521         break;
522 
523     case PR_DIRECTIVE_ENDIF:
524 
525         PrDbgPrint ("Executing", "endif");
526 
527         /* Pop the owning #if/#ifdef/#ifndef */
528 
529         if (ACPI_FAILURE (PrPopDirective ()))
530         {
531             PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
532                 THIS_TOKEN_OFFSET (DirectiveToken));
533         }
534         return;
535 
536     default:
537         break;
538     }
539 
540     /* Most directives have at least one argument */
541 
542     if (Gbl_DirectiveInfo[Directive].ArgCount == 1)
543     {
544         Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
545         if (!Token)
546         {
547             goto SyntaxError;
548         }
549     }
550 
551     /*
552      * At this point, if we are ignoring the current code block,
553      * do not process any more directives (i.e., ignore them also.)
554      * For "if" style directives, open/push a new block anyway. We
555      * must do this to keep track of #endif directives
556      */
557     if (Gbl_IgnoringThisCodeBlock)
558     {
559         switch (Directive)
560         {
561         case PR_DIRECTIVE_IF:
562         case PR_DIRECTIVE_IFDEF:
563         case PR_DIRECTIVE_IFNDEF:
564 
565             PrPushDirective (Directive, Token);
566             PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
567             break;
568 
569         default:
570             break;
571         }
572 
573         return;
574     }
575 
576     /*
577      * Execute the directive
578      */
579     PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
580 
581     switch (Directive)
582     {
583     case PR_DIRECTIVE_IF:
584 
585         TokenOffset = Token - Gbl_MainTokenBuffer;
586 
587         /* Need to expand #define macros in the expression string first */
588 
589         Status = PrResolveIntegerExpression (
590             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
591         if (ACPI_FAILURE (Status))
592         {
593             return;
594         }
595 
596         PrPushDirective (Directive, Token);
597         if (!Value)
598         {
599             Gbl_IgnoringThisCodeBlock = TRUE;
600         }
601 
602         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
603             "Resolved #if: %8.8X%8.8X %s\n",
604             Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
605             Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
606         break;
607 
608     case PR_DIRECTIVE_IFDEF:
609 
610         PrPushDirective (Directive, Token);
611         if (!PrMatchDefine (Token))
612         {
613             Gbl_IgnoringThisCodeBlock = TRUE;
614         }
615 
616         PrDbgPrint ("Evaluated", "ifdef");
617         break;
618 
619     case PR_DIRECTIVE_IFNDEF:
620 
621         PrPushDirective (Directive, Token);
622         if (PrMatchDefine (Token))
623         {
624             Gbl_IgnoringThisCodeBlock = TRUE;
625         }
626 
627         PrDbgPrint ("Evaluated", "ifndef");
628         break;
629 
630     case PR_DIRECTIVE_DEFINE:
631         /*
632          * By definition, if first char after the name is a paren,
633          * this is a function macro.
634          */
635         TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
636         if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
637         {
638 #ifndef MACROS_SUPPORTED
639             AcpiOsPrintf ("%s ERROR - line %u: #define macros are not supported yet\n",
640                 Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber);
641             exit(1);
642 #else
643             PrAddMacro (Token, Next);
644 #endif
645         }
646         else
647         {
648             /* Use the remainder of the line for the #define */
649 
650             Token2 = *Next;
651             if (Token2)
652             {
653                 while ((*Token2 == ' ') || (*Token2 == '\t'))
654                 {
655                     Token2++;
656                 }
657                 End = Token2;
658                 while (*End != '\n')
659                 {
660                     End++;
661                 }
662                 *End = 0;
663             }
664             else
665             {
666                 Token2 = "";
667             }
668 #if 0
669             Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
670             if (!Token2)
671             {
672                 Token2 = "";
673             }
674 #endif
675             DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
676                 "New #define: %s->%s\n",
677                 Gbl_CurrentLineNumber, Token, Token2);
678 
679             PrAddDefine (Token, Token2, FALSE);
680         }
681         break;
682 
683     case PR_DIRECTIVE_ERROR:
684 
685         /* Note: No macro expansion */
686 
687         PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
688             THIS_TOKEN_OFFSET (Token));
689 
690         Gbl_SourceLine = 0;
691         Gbl_NextError = Gbl_ErrorLog;
692         CmCleanupAndExit ();
693         exit(1);
694 
695     case PR_DIRECTIVE_INCLUDE:
696 
697         Token = PrGetNextToken (NULL, " \"<>", Next);
698         if (!Token)
699         {
700             goto SyntaxError;
701         }
702 
703         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
704             "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
705             Token, Gbl_CurrentLineNumber);
706 
707         PrOpenIncludeFile (Token);
708         break;
709 
710     case PR_DIRECTIVE_LINE:
711 
712         TokenOffset = Token - Gbl_MainTokenBuffer;
713 
714         Status = PrResolveIntegerExpression (
715             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
716         if (ACPI_FAILURE (Status))
717         {
718             return;
719         }
720 
721         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
722             "User #line invocation %s\n", Gbl_CurrentLineNumber,
723             Token);
724 
725         /* Update local line numbers */
726 
727         Gbl_CurrentLineNumber = (UINT32) Value;
728         Gbl_PreviousLineNumber = 0;
729 
730         /* Emit #line into the preprocessor file */
731 
732         FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
733             Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
734         break;
735 
736     case PR_DIRECTIVE_PRAGMA:
737 
738         if (!strcmp (Token, "disable"))
739         {
740             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
741             if (!Token)
742             {
743                 goto SyntaxError;
744             }
745 
746             TokenOffset = Token - Gbl_MainTokenBuffer;
747             AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
748         }
749         else if (!strcmp (Token, "message"))
750         {
751             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
752             if (!Token)
753             {
754                 goto SyntaxError;
755             }
756 
757             TokenOffset = Token - Gbl_MainTokenBuffer;
758             AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
759         }
760         else
761         {
762             PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
763                 THIS_TOKEN_OFFSET (Token));
764             return;
765         }
766 
767         break;
768 
769     case PR_DIRECTIVE_UNDEF:
770 
771         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
772             "#undef: %s\n", Gbl_CurrentLineNumber, Token);
773 
774         PrRemoveDefine (Token);
775         break;
776 
777     case PR_DIRECTIVE_WARNING:
778 
779         PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
780             THIS_TOKEN_OFFSET (Token));
781         break;
782 
783     default:
784 
785         /* Should never get here */
786         DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
787             "Unrecognized directive: %u\n",
788             Gbl_CurrentLineNumber, Directive);
789         break;
790     }
791 
792     return;
793 
794 SyntaxError:
795 
796     PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
797         THIS_TOKEN_OFFSET (DirectiveToken));
798     return;
799 }
800 
801 
802 /*******************************************************************************
803  *
804  * FUNCTION:    PrMatchDirective
805  *
806  * PARAMETERS:  Directive           - Pointer to directive name token
807  *
808  * RETURN:      Index into command array, -1 if not found
809  *
810  * DESCRIPTION: Lookup the incoming directive in the known directives table.
811  *
812  ******************************************************************************/
813 
814 static int
815 PrMatchDirective (
816     char                    *Directive)
817 {
818     int                     i;
819 
820 
821     if (!Directive || Directive[0] == 0)
822     {
823         return (ASL_DIRECTIVE_NOT_FOUND);
824     }
825 
826     for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
827     {
828         if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
829         {
830             return (i);
831         }
832     }
833 
834     return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
835 }
836 
837 
838 /*******************************************************************************
839  *
840  * FUNCTION:    PrPushDirective
841  *
842  * PARAMETERS:  Directive           - Encoded directive ID
843  *              Argument            - String containing argument to the
844  *                                    directive
845  *
846  * RETURN:      None
847  *
848  * DESCRIPTION: Push an item onto the directive stack. Used for processing
849  *              nested #if/#else type conditional compilation directives.
850  *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
851  *              a block.
852  *
853  ******************************************************************************/
854 
855 static void
856 PrPushDirective (
857     int                     Directive,
858     char                    *Argument)
859 {
860     DIRECTIVE_INFO          *Info;
861 
862 
863     /* Allocate and populate a stack info item */
864 
865     Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
866 
867     Info->Next = Gbl_DirectiveStack;
868     Info->Directive = Directive;
869     Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
870     strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
871 
872     DbgPrint (ASL_DEBUG_OUTPUT,
873         "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
874         Gbl_CurrentLineNumber, Gbl_IfDepth,
875         Gbl_IgnoringThisCodeBlock ? "I" : "E",
876         Gbl_IfDepth * 4, " ",
877         Gbl_DirectiveInfo[Directive].Name,
878         Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
879 
880     /* Push new item */
881 
882     Gbl_DirectiveStack = Info;
883     Gbl_IfDepth++;
884 }
885 
886 
887 /*******************************************************************************
888  *
889  * FUNCTION:    PrPopDirective
890  *
891  * PARAMETERS:  None
892  *
893  * RETURN:      Status. Error if the stack is empty.
894  *
895  * DESCRIPTION: Pop an item off the directive stack. Used for processing
896  *              nested #if/#else type conditional compilation directives.
897  *              Specifically: Used on detection of #elif and #endif to remove
898  *              the original #if/#ifdef/#ifndef from the stack and close
899  *              the block.
900  *
901  ******************************************************************************/
902 
903 static ACPI_STATUS
904 PrPopDirective (
905     void)
906 {
907     DIRECTIVE_INFO          *Info;
908 
909 
910     /* Check for empty stack */
911 
912     Info = Gbl_DirectiveStack;
913     if (!Info)
914     {
915         return (AE_ERROR);
916     }
917 
918     /* Pop one item, keep globals up-to-date */
919 
920     Gbl_IfDepth--;
921     Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
922     Gbl_DirectiveStack = Info->Next;
923 
924     DbgPrint (ASL_DEBUG_OUTPUT,
925         "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
926         Gbl_CurrentLineNumber, Gbl_IfDepth,
927         Gbl_IgnoringThisCodeBlock ? "I" : "E",
928         Gbl_IfDepth * 4, " ",
929         Gbl_DirectiveInfo[Info->Directive].Name,
930         Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
931 
932     ACPI_FREE (Info);
933     return (AE_OK);
934 }
935 
936 
937 /*******************************************************************************
938  *
939  * FUNCTION:    PrDbgPrint
940  *
941  * PARAMETERS:  Action              - Action being performed
942  *              DirectiveName       - Directive being processed
943  *
944  * RETURN:      None
945  *
946  * DESCRIPTION: Special debug print for directive processing.
947  *
948  ******************************************************************************/
949 
950 static void
951 PrDbgPrint (
952     char                    *Action,
953     char                    *DirectiveName)
954 {
955 
956     DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
957         "%*s %s #%s, Depth %u\n",
958         Gbl_CurrentLineNumber, Gbl_IfDepth,
959         Gbl_IgnoringThisCodeBlock ? "I" : "E",
960         Gbl_IfDepth * 4, " ",
961         Action, DirectiveName, Gbl_IfDepth);
962 }
963