xref: /freebsd/sys/contrib/dev/acpica/compiler/prscan.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
1 /******************************************************************************
2  *
3  * Module Name: prscan - Preprocessor start-up and file scan module
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2015, 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 void
71 PrGetNextLineInit (
72     void);
73 
74 static UINT32
75 PrGetNextLine (
76     FILE                    *Handle);
77 
78 static int
79 PrMatchDirective (
80     char                    *Directive);
81 
82 static void
83 PrPushDirective (
84     int                     Directive,
85     char                    *Argument);
86 
87 static ACPI_STATUS
88 PrPopDirective (
89     void);
90 
91 static void
92 PrDbgPrint (
93     char                    *Action,
94     char                    *DirectiveName);
95 
96 static void
97 PrDoIncludeBuffer (
98     char                    *Pathname,
99     char                    *BufferName);
100 
101 static void
102 PrDoIncludeFile (
103     char                    *Pathname);
104 
105 
106 /*
107  * Supported preprocessor directives
108  * Each entry is of the form "Name, ArgumentCount"
109  */
110 static const PR_DIRECTIVE_INFO      Gbl_DirectiveInfo[] =
111 {
112     {"define",          1},
113     {"elif",            0}, /* Converted to #else..#if internally */
114     {"else",            0},
115     {"endif",           0},
116     {"error",           1},
117     {"if",              1},
118     {"ifdef",           1},
119     {"ifndef",          1},
120     {"include",         0}, /* Argument is not standard format, so just use 0 here */
121     {"includebuffer",   0}, /* Argument is not standard format, so just use 0 here */
122     {"line",            1},
123     {"pragma",          1},
124     {"undef",           1},
125     {"warning",         1},
126     {NULL,              0}
127 };
128 
129 /* This table must match ordering of above table exactly */
130 
131 enum Gbl_DirectiveIndexes
132 {
133     PR_DIRECTIVE_DEFINE = 0,
134     PR_DIRECTIVE_ELIF,
135     PR_DIRECTIVE_ELSE,
136     PR_DIRECTIVE_ENDIF,
137     PR_DIRECTIVE_ERROR,
138     PR_DIRECTIVE_IF,
139     PR_DIRECTIVE_IFDEF,
140     PR_DIRECTIVE_IFNDEF,
141     PR_DIRECTIVE_INCLUDE,
142     PR_DIRECTIVE_INCLUDEBUFFER,
143     PR_DIRECTIVE_LINE,
144     PR_DIRECTIVE_PRAGMA,
145     PR_DIRECTIVE_UNDEF,
146     PR_DIRECTIVE_WARNING
147 };
148 
149 #define ASL_DIRECTIVE_NOT_FOUND     -1
150 
151 
152 /*******************************************************************************
153  *
154  * FUNCTION:    PrInitializePreprocessor
155  *
156  * PARAMETERS:  None
157  *
158  * RETURN:      None
159  *
160  * DESCRIPTION: Startup initialization for the Preprocessor.
161  *
162  ******************************************************************************/
163 
164 void
165 PrInitializePreprocessor (
166     void)
167 {
168     /* Init globals and the list of #defines */
169 
170     PrInitializeGlobals ();
171     Gbl_DefineList = NULL;
172 }
173 
174 
175 /*******************************************************************************
176  *
177  * FUNCTION:    PrInitializeGlobals
178  *
179  * PARAMETERS:  None
180  *
181  * RETURN:      None
182  *
183  * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup
184  *              initialization and re-initialization between compiles during
185  *              a multiple source file compile.
186  *
187  ******************************************************************************/
188 
189 void
190 PrInitializeGlobals (
191     void)
192 {
193     /* Init globals */
194 
195     Gbl_InputFileList = NULL;
196     Gbl_CurrentLineNumber = 1;
197     Gbl_PreprocessorLineNumber = 1;
198     Gbl_PreprocessorError = FALSE;
199 
200     /* These are used to track #if/#else blocks (possibly nested) */
201 
202     Gbl_IfDepth = 0;
203     Gbl_IgnoringThisCodeBlock = FALSE;
204     Gbl_DirectiveStack = NULL;
205 }
206 
207 
208 /*******************************************************************************
209  *
210  * FUNCTION:    PrTerminatePreprocessor
211  *
212  * PARAMETERS:  None
213  *
214  * RETURN:      None
215  *
216  * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any
217  *              defines that were specified on the command line, in order to
218  *              support multiple compiles with a single compiler invocation.
219  *
220  ******************************************************************************/
221 
222 void
223 PrTerminatePreprocessor (
224     void)
225 {
226     PR_DEFINE_INFO          *DefineInfo;
227 
228 
229     /*
230      * The persistent defines (created on the command line) are always at the
231      * end of the list. We save them.
232      */
233     while ((Gbl_DefineList) && (!Gbl_DefineList->Persist))
234     {
235         DefineInfo = Gbl_DefineList;
236         Gbl_DefineList = DefineInfo->Next;
237 
238         ACPI_FREE (DefineInfo->Replacement);
239         ACPI_FREE (DefineInfo->Identifier);
240         ACPI_FREE (DefineInfo);
241     }
242 }
243 
244 
245 /*******************************************************************************
246  *
247  * FUNCTION:    PrDoPreprocess
248  *
249  * PARAMETERS:  None
250  *
251  * RETURN:      None
252  *
253  * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must
254  *              be already open. Handles multiple input files via the
255  *              #include directive.
256  *
257  ******************************************************************************/
258 
259 void
260 PrDoPreprocess (
261     void)
262 {
263     BOOLEAN                 MoreInputFiles;
264 
265 
266     DbgPrint (ASL_DEBUG_OUTPUT, "Starting preprocessing phase\n\n");
267 
268 
269     FlSeekFile (ASL_FILE_INPUT, 0);
270     PrDumpPredefinedNames ();
271 
272     /* Main preprocessor loop, handles include files */
273 
274     do
275     {
276         PrPreprocessInputFile ();
277         MoreInputFiles = PrPopInputFileStack ();
278 
279     } while (MoreInputFiles);
280 
281     /* Point compiler input to the new preprocessor output file (.pre) */
282 
283     FlCloseFile (ASL_FILE_INPUT);
284     Gbl_Files[ASL_FILE_INPUT].Handle = Gbl_Files[ASL_FILE_PREPROCESSOR].Handle;
285     AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle;
286 
287     /* Reset globals to allow compiler to run */
288 
289     FlSeekFile (ASL_FILE_INPUT, 0);
290     if (!Gbl_PreprocessOnly)
291     {
292         Gbl_CurrentLineNumber = 0;
293     }
294 
295     DbgPrint (ASL_DEBUG_OUTPUT, "Preprocessing phase complete \n\n");
296 }
297 
298 
299 /*******************************************************************************
300  *
301  * FUNCTION:    PrPreprocessInputFile
302  *
303  * PARAMETERS:  None
304  *
305  * RETURN:      None
306  *
307  * DESCRIPTION: Preprocess one entire file, line-by-line.
308  *
309  * Input:  Raw user ASL from ASL_FILE_INPUT
310  * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR and
311  *         (optionally) ASL_FILE_PREPROCESSOR_USER
312  *
313  ******************************************************************************/
314 
315 static void
316 PrPreprocessInputFile (
317     void)
318 {
319     UINT32                  Status;
320     char                    *Token;
321     char                    *ReplaceString;
322     PR_DEFINE_INFO          *DefineInfo;
323     ACPI_SIZE               TokenOffset;
324     char                    *Next;
325     int                     OffsetAdjust;
326 
327 
328     PrGetNextLineInit ();
329 
330     /* Scan source line-by-line and process directives. Then write the .i file */
331 
332     while ((Status = PrGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF)
333     {
334         Gbl_CurrentLineNumber++;
335         Gbl_LogicalLineNumber++;
336 
337         if ((Status == ASL_WITHIN_COMMENT) ||
338             (Status == ASL_BLANK_LINE))
339         {
340             goto WriteEntireLine;
341         }
342 
343         /* Need a copy of the input line for strok() */
344 
345         strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
346         Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
347         OffsetAdjust = 0;
348 
349         /* All preprocessor directives must begin with '#' */
350 
351         if (Token && (*Token == '#'))
352         {
353             if (strlen (Token) == 1)
354             {
355                 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
356             }
357             else
358             {
359                 Token++;    /* Skip leading # */
360             }
361 
362             /* Execute the directive, do not write line to output file */
363 
364             PrDoDirective (Token, &Next);
365             continue;
366         }
367 
368         /*
369          * If we are currently within the part of an IF/ELSE block that is
370          * FALSE, ignore the line and do not write it to the output file.
371          * This continues until an #else or #endif is encountered.
372          */
373         if (Gbl_IgnoringThisCodeBlock)
374         {
375             continue;
376         }
377 
378         /* Match and replace all #defined names within this source line */
379 
380         while (Token)
381         {
382             DefineInfo = PrMatchDefine (Token);
383             if (DefineInfo)
384             {
385                 if (DefineInfo->Body)
386                 {
387                     /* This is a macro */
388 
389                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
390                         "Matched Macro: %s->%s\n",
391                         Gbl_CurrentLineNumber, DefineInfo->Identifier,
392                         DefineInfo->Replacement);
393 
394                     PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
395                         DefineInfo, &Next);
396                 }
397                 else
398                 {
399                     ReplaceString = DefineInfo->Replacement;
400 
401                     /* Replace the name in the original line buffer */
402 
403                     TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
404                     PrReplaceData (
405                         &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
406                         ReplaceString, strlen (ReplaceString));
407 
408                     /* Adjust for length difference between old and new name length */
409 
410                     OffsetAdjust += strlen (ReplaceString) - strlen (Token);
411 
412                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
413                         "Matched #define: %s->%s\n",
414                         Gbl_CurrentLineNumber, Token,
415                         *ReplaceString ? ReplaceString : "(NULL STRING)");
416                 }
417             }
418 
419             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
420         }
421 
422         Gbl_PreprocessorLineNumber++;
423 
424 
425 WriteEntireLine:
426         /*
427          * Now we can write the possibly modified source line to the
428          * preprocessor file(s).
429          */
430         FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
431             strlen (Gbl_CurrentLineBuffer));
432     }
433 }
434 
435 
436 /*******************************************************************************
437  *
438  * FUNCTION:    PrDoDirective
439  *
440  * PARAMETERS:  Directive               - Pointer to directive name token
441  *              Next                    - "Next" buffer from GetNextToken
442  *
443  * RETURN:      None.
444  *
445  * DESCRIPTION: Main processing for all preprocessor directives
446  *
447  ******************************************************************************/
448 
449 static void
450 PrDoDirective (
451     char                    *DirectiveToken,
452     char                    **Next)
453 {
454     char                    *Token = Gbl_MainTokenBuffer;
455     char                    *Token2 = NULL;
456     char                    *End;
457     UINT64                  Value;
458     ACPI_SIZE               TokenOffset;
459     int                     Directive;
460     ACPI_STATUS             Status;
461 
462 
463     if (!DirectiveToken)
464     {
465         goto SyntaxError;
466     }
467 
468     Directive = PrMatchDirective (DirectiveToken);
469     if (Directive == ASL_DIRECTIVE_NOT_FOUND)
470     {
471         PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
472             THIS_TOKEN_OFFSET (DirectiveToken));
473 
474         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
475             "#%s: Unknown directive\n",
476             Gbl_CurrentLineNumber, DirectiveToken);
477         return;
478     }
479 
480     /*
481      * Emit a line directive into the preprocessor file (.pre) after
482      * every matched directive. This is passed through to the compiler
483      * so that error/warning messages are kept in sync with the
484      * original source file.
485      */
486     FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\" // #%s\n",
487         Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename,
488         Gbl_DirectiveInfo[Directive].Name);
489 
490     /*
491      * If we are currently ignoring this block and we encounter a #else or
492      * #elif, we must ignore their blocks also if the parent block is also
493      * being ignored.
494      */
495     if (Gbl_IgnoringThisCodeBlock)
496     {
497         switch (Directive)
498         {
499         case PR_DIRECTIVE_ELSE:
500         case PR_DIRECTIVE_ELIF:
501 
502             if (Gbl_DirectiveStack && Gbl_DirectiveStack->IgnoringThisCodeBlock)
503             {
504                 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
505                 return;
506             }
507             break;
508 
509         default:
510             break;
511         }
512     }
513 
514     /*
515      * Need to always check for #else, #elif, #endif regardless of
516      * whether we are ignoring the current code block, since these
517      * are conditional code block terminators.
518      */
519     switch (Directive)
520     {
521     case PR_DIRECTIVE_ELSE:
522 
523         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
524         PrDbgPrint ("Executing", "else block");
525         return;
526 
527     case PR_DIRECTIVE_ELIF:
528 
529         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
530         Directive = PR_DIRECTIVE_IF;
531 
532         if (Gbl_IgnoringThisCodeBlock == TRUE)
533         {
534             /* Not executing the ELSE part -- all done here */
535             PrDbgPrint ("Ignoring", "elif block");
536             return;
537         }
538 
539         /*
540          * After this, we will execute the IF part further below.
541          * First, however, pop off the original #if directive.
542          */
543         if (ACPI_FAILURE (PrPopDirective ()))
544         {
545             PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
546                 THIS_TOKEN_OFFSET (DirectiveToken));
547         }
548 
549         PrDbgPrint ("Executing", "elif block");
550         break;
551 
552     case PR_DIRECTIVE_ENDIF:
553 
554         PrDbgPrint ("Executing", "endif");
555 
556         /* Pop the owning #if/#ifdef/#ifndef */
557 
558         if (ACPI_FAILURE (PrPopDirective ()))
559         {
560             PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
561                 THIS_TOKEN_OFFSET (DirectiveToken));
562         }
563         return;
564 
565     default:
566         break;
567     }
568 
569     /* Most directives have at least one argument */
570 
571     if (Gbl_DirectiveInfo[Directive].ArgCount >= 1)
572     {
573         Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
574         if (!Token)
575         {
576             goto SyntaxError;
577         }
578     }
579 
580     if (Gbl_DirectiveInfo[Directive].ArgCount >= 2)
581     {
582         Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
583         if (!Token2)
584         {
585             goto SyntaxError;
586         }
587     }
588 
589     /*
590      * At this point, if we are ignoring the current code block,
591      * do not process any more directives (i.e., ignore them also.)
592      * For "if" style directives, open/push a new block anyway. We
593      * must do this to keep track of #endif directives
594      */
595     if (Gbl_IgnoringThisCodeBlock)
596     {
597         switch (Directive)
598         {
599         case PR_DIRECTIVE_IF:
600         case PR_DIRECTIVE_IFDEF:
601         case PR_DIRECTIVE_IFNDEF:
602 
603             PrPushDirective (Directive, Token);
604             PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
605             break;
606 
607         default:
608             break;
609         }
610 
611         return;
612     }
613 
614     /*
615      * Execute the directive
616      */
617     PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
618 
619     switch (Directive)
620     {
621     case PR_DIRECTIVE_IF:
622 
623         TokenOffset = Token - Gbl_MainTokenBuffer;
624 
625         /* Need to expand #define macros in the expression string first */
626 
627         Status = PrResolveIntegerExpression (
628             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
629         if (ACPI_FAILURE (Status))
630         {
631             return;
632         }
633 
634         PrPushDirective (Directive, Token);
635         if (!Value)
636         {
637             Gbl_IgnoringThisCodeBlock = TRUE;
638         }
639 
640         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
641             "Resolved #if: %8.8X%8.8X %s\n",
642             Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
643             Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
644         break;
645 
646     case PR_DIRECTIVE_IFDEF:
647 
648         PrPushDirective (Directive, Token);
649         if (!PrMatchDefine (Token))
650         {
651             Gbl_IgnoringThisCodeBlock = TRUE;
652         }
653 
654         PrDbgPrint ("Evaluated", "ifdef");
655         break;
656 
657     case PR_DIRECTIVE_IFNDEF:
658 
659         PrPushDirective (Directive, Token);
660         if (PrMatchDefine (Token))
661         {
662             Gbl_IgnoringThisCodeBlock = TRUE;
663         }
664 
665         PrDbgPrint ("Evaluated", "ifndef");
666         break;
667 
668     case PR_DIRECTIVE_DEFINE:
669         /*
670          * By definition, if first char after the name is a paren,
671          * this is a function macro.
672          */
673         TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
674         if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
675         {
676 #ifndef MACROS_SUPPORTED
677             AcpiOsPrintf ("%s ERROR - line %u: #define macros are not supported yet\n",
678                 Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber);
679             exit(1);
680 #else
681             PrAddMacro (Token, Next);
682 #endif
683         }
684         else
685         {
686             /* Use the remainder of the line for the #define */
687 
688             Token2 = *Next;
689             if (Token2)
690             {
691                 while ((*Token2 == ' ') || (*Token2 == '\t'))
692                 {
693                     Token2++;
694                 }
695                 End = Token2;
696                 while (*End != '\n')
697                 {
698                     End++;
699                 }
700                 *End = 0;
701             }
702             else
703             {
704                 Token2 = "";
705             }
706 #if 0
707             Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
708             if (!Token2)
709             {
710                 Token2 = "";
711             }
712 #endif
713             DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
714                 "New #define: %s->%s\n",
715                 Gbl_LogicalLineNumber, Token, Token2);
716 
717             PrAddDefine (Token, Token2, FALSE);
718         }
719         break;
720 
721     case PR_DIRECTIVE_ERROR:
722 
723         /* Note: No macro expansion */
724 
725         PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
726             THIS_TOKEN_OFFSET (Token));
727 
728         Gbl_SourceLine = 0;
729         Gbl_NextError = Gbl_ErrorLog;
730         CmCleanupAndExit ();
731         exit(1);
732 
733     case PR_DIRECTIVE_INCLUDE:
734 
735         Token = PrGetNextToken (NULL, " \"<>", Next);
736         if (!Token)
737         {
738             goto SyntaxError;
739         }
740 
741         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
742             "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
743             Token, Gbl_CurrentLineNumber);
744 
745         PrDoIncludeFile (Token);
746         break;
747 
748     case PR_DIRECTIVE_INCLUDEBUFFER:
749 
750         Token = PrGetNextToken (NULL, " \"<>", Next);
751         if (!Token)
752         {
753             goto SyntaxError;
754         }
755 
756         Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
757         if (!Token2)
758         {
759             goto SyntaxError;
760         }
761 
762         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
763             "Start #includebuffer input from file \"%s\", buffer name %s\n",
764             Gbl_CurrentLineNumber, Token, Token2);
765 
766         PrDoIncludeBuffer (Token, Token2);
767         break;
768 
769     case PR_DIRECTIVE_LINE:
770 
771         TokenOffset = Token - Gbl_MainTokenBuffer;
772 
773         Status = PrResolveIntegerExpression (
774             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
775         if (ACPI_FAILURE (Status))
776         {
777             return;
778         }
779 
780         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
781             "User #line invocation %s\n", Gbl_CurrentLineNumber,
782             Token);
783 
784         Gbl_CurrentLineNumber = (UINT32) Value;
785 
786         /* Emit #line into the preprocessor file */
787 
788         FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
789             Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
790         break;
791 
792     case PR_DIRECTIVE_PRAGMA:
793 
794         if (!strcmp (Token, "disable"))
795         {
796             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
797             if (!Token)
798             {
799                 goto SyntaxError;
800             }
801 
802             TokenOffset = Token - Gbl_MainTokenBuffer;
803             AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
804         }
805         else if (!strcmp (Token, "message"))
806         {
807             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
808             if (!Token)
809             {
810                 goto SyntaxError;
811             }
812 
813             TokenOffset = Token - Gbl_MainTokenBuffer;
814             AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
815         }
816         else
817         {
818             PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
819                 THIS_TOKEN_OFFSET (Token));
820             return;
821         }
822 
823         break;
824 
825     case PR_DIRECTIVE_UNDEF:
826 
827         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
828             "#undef: %s\n", Gbl_CurrentLineNumber, Token);
829 
830         PrRemoveDefine (Token);
831         break;
832 
833     case PR_DIRECTIVE_WARNING:
834 
835         PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
836             THIS_TOKEN_OFFSET (Token));
837 
838         Gbl_SourceLine = 0;
839         Gbl_NextError = Gbl_ErrorLog;
840         break;
841 
842     default:
843 
844         /* Should never get here */
845         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
846             "Unrecognized directive: %u\n",
847             Gbl_CurrentLineNumber, Directive);
848         break;
849     }
850 
851     return;
852 
853 SyntaxError:
854 
855     PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
856         THIS_TOKEN_OFFSET (DirectiveToken));
857     return;
858 }
859 
860 
861 /*******************************************************************************
862  *
863  * FUNCTION:    PrGetNextLine, PrGetNextLineInit
864  *
865  * PARAMETERS:  Handle              - Open file handle for the source file
866  *
867  * RETURN:      Status of the GetLine operation:
868  *              AE_OK               - Normal line, OK status
869  *              ASL_WITHIN_COMMENT  - Line is part of a multi-line comment
870  *              ASL_EOF             - End-of-file reached
871  *
872  * DESCRIPTION: Get the next text line from the input file. Does not strip
873  *              comments.
874  *
875  ******************************************************************************/
876 
877 #define PR_NORMAL_TEXT          0
878 #define PR_MULTI_LINE_COMMENT   1
879 #define PR_SINGLE_LINE_COMMENT  2
880 #define PR_QUOTED_STRING        3
881 
882 static UINT8                    AcpiGbl_LineScanState = PR_NORMAL_TEXT;
883 
884 static void
885 PrGetNextLineInit (
886     void)
887 {
888     AcpiGbl_LineScanState = 0;
889 }
890 
891 static UINT32
892 PrGetNextLine (
893     FILE                    *Handle)
894 {
895     UINT32                  i;
896     int                     c = 0;
897     int                     PreviousChar;
898 
899 
900     /* Always clear the global line buffer */
901 
902     memset (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize);
903     for (i = 0; ;)
904     {
905         /*
906          * If line is too long, expand the line buffers. Also increases
907          * Gbl_LineBufferSize.
908          */
909         if (i >= Gbl_LineBufferSize)
910         {
911             UtExpandLineBuffers ();
912         }
913 
914         PreviousChar = c;
915         c = getc (Handle);
916         if (c == EOF)
917         {
918             return (ASL_EOF);
919         }
920 
921         /* Update state machine as necessary */
922 
923         switch (AcpiGbl_LineScanState)
924         {
925         case PR_NORMAL_TEXT:
926 
927             /* Check for multi-line comment start */
928 
929             if ((PreviousChar == '/') && (c == '*'))
930             {
931                 AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT;
932             }
933 
934             /* Check for single-line comment start */
935 
936             else if ((PreviousChar == '/') && (c == '/'))
937             {
938                 AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT;
939             }
940 
941             /* Check for quoted string start */
942 
943             else if (PreviousChar == '"')
944             {
945                 AcpiGbl_LineScanState = PR_QUOTED_STRING;
946             }
947             break;
948 
949         case PR_QUOTED_STRING:
950 
951             if (PreviousChar == '"')
952             {
953                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
954             }
955             break;
956 
957         case PR_MULTI_LINE_COMMENT:
958 
959             /* Check for multi-line comment end */
960 
961             if ((PreviousChar == '*') && (c == '/'))
962             {
963                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
964             }
965             break;
966 
967         case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */
968         default:
969             break;
970         }
971 
972         /* Always copy the character into line buffer */
973 
974         Gbl_CurrentLineBuffer[i] = (char) c;
975         i++;
976 
977         /* Always exit on end-of-line */
978 
979         if (c == '\n')
980         {
981             /* Handle multi-line comments */
982 
983             if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT)
984             {
985                 return (ASL_WITHIN_COMMENT);
986             }
987 
988             /* End of single-line comment */
989 
990             if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT)
991             {
992                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
993                 return (AE_OK);
994             }
995 
996             /* Blank line */
997 
998             if (i == 1)
999             {
1000                 return (ASL_BLANK_LINE);
1001             }
1002             return (AE_OK);
1003         }
1004     }
1005 }
1006 
1007 
1008 /*******************************************************************************
1009  *
1010  * FUNCTION:    PrMatchDirective
1011  *
1012  * PARAMETERS:  Directive           - Pointer to directive name token
1013  *
1014  * RETURN:      Index into command array, -1 if not found
1015  *
1016  * DESCRIPTION: Lookup the incoming directive in the known directives table.
1017  *
1018  ******************************************************************************/
1019 
1020 static int
1021 PrMatchDirective (
1022     char                    *Directive)
1023 {
1024     int                     i;
1025 
1026 
1027     if (!Directive || Directive[0] == 0)
1028     {
1029         return (ASL_DIRECTIVE_NOT_FOUND);
1030     }
1031 
1032     for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
1033     {
1034         if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
1035         {
1036             return (i);
1037         }
1038     }
1039 
1040     return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
1041 }
1042 
1043 
1044 /*******************************************************************************
1045  *
1046  * FUNCTION:    PrPushDirective
1047  *
1048  * PARAMETERS:  Directive           - Encoded directive ID
1049  *              Argument            - String containing argument to the
1050  *                                    directive
1051  *
1052  * RETURN:      None
1053  *
1054  * DESCRIPTION: Push an item onto the directive stack. Used for processing
1055  *              nested #if/#else type conditional compilation directives.
1056  *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
1057  *              a block.
1058  *
1059  ******************************************************************************/
1060 
1061 static void
1062 PrPushDirective (
1063     int                     Directive,
1064     char                    *Argument)
1065 {
1066     DIRECTIVE_INFO          *Info;
1067 
1068 
1069     /* Allocate and populate a stack info item */
1070 
1071     Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
1072 
1073     Info->Next = Gbl_DirectiveStack;
1074     Info->Directive = Directive;
1075     Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
1076     strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
1077 
1078     DbgPrint (ASL_DEBUG_OUTPUT,
1079         "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
1080         Gbl_CurrentLineNumber, Gbl_IfDepth,
1081         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1082         Gbl_IfDepth * 4, " ",
1083         Gbl_DirectiveInfo[Directive].Name,
1084         Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1085 
1086     /* Push new item */
1087 
1088     Gbl_DirectiveStack = Info;
1089     Gbl_IfDepth++;
1090 }
1091 
1092 
1093 /*******************************************************************************
1094  *
1095  * FUNCTION:    PrPopDirective
1096  *
1097  * PARAMETERS:  None
1098  *
1099  * RETURN:      Status. Error if the stack is empty.
1100  *
1101  * DESCRIPTION: Pop an item off the directive stack. Used for processing
1102  *              nested #if/#else type conditional compilation directives.
1103  *              Specifically: Used on detection of #elif and #endif to remove
1104  *              the original #if/#ifdef/#ifndef from the stack and close
1105  *              the block.
1106  *
1107  ******************************************************************************/
1108 
1109 static ACPI_STATUS
1110 PrPopDirective (
1111     void)
1112 {
1113     DIRECTIVE_INFO          *Info;
1114 
1115 
1116     /* Check for empty stack */
1117 
1118     Info = Gbl_DirectiveStack;
1119     if (!Info)
1120     {
1121         return (AE_ERROR);
1122     }
1123 
1124     /* Pop one item, keep globals up-to-date */
1125 
1126     Gbl_IfDepth--;
1127     Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
1128     Gbl_DirectiveStack = Info->Next;
1129 
1130     DbgPrint (ASL_DEBUG_OUTPUT,
1131         "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
1132         Gbl_CurrentLineNumber, Gbl_IfDepth,
1133         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1134         Gbl_IfDepth * 4, " ",
1135         Gbl_DirectiveInfo[Info->Directive].Name,
1136         Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1137 
1138     ACPI_FREE (Info);
1139     return (AE_OK);
1140 }
1141 
1142 
1143 /*******************************************************************************
1144  *
1145  * FUNCTION:    PrDbgPrint
1146  *
1147  * PARAMETERS:  Action              - Action being performed
1148  *              DirectiveName       - Directive being processed
1149  *
1150  * RETURN:      None
1151  *
1152  * DESCRIPTION: Special debug print for directive processing.
1153  *
1154  ******************************************************************************/
1155 
1156 static void
1157 PrDbgPrint (
1158     char                    *Action,
1159     char                    *DirectiveName)
1160 {
1161 
1162     DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
1163         "%*s %s #%s, IfDepth %u\n",
1164         Gbl_CurrentLineNumber, Gbl_IfDepth,
1165         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1166         Gbl_IfDepth * 4, " ",
1167         Action, DirectiveName, Gbl_IfDepth);
1168 }
1169 
1170 
1171 /*******************************************************************************
1172  *
1173  * FUNCTION:    PrDoIncludeFile
1174  *
1175  * PARAMETERS:  Pathname                - Name of the input file
1176  *
1177  * RETURN:      None.
1178  *
1179  * DESCRIPTION: Open an include file, from #include.
1180  *
1181  ******************************************************************************/
1182 
1183 static void
1184 PrDoIncludeFile (
1185     char                    *Pathname)
1186 {
1187     char                    *FullPathname;
1188 
1189 
1190     (void) PrOpenIncludeFile (Pathname, "r", &FullPathname);
1191 }
1192 
1193 
1194 /*******************************************************************************
1195  *
1196  * FUNCTION:    PrDoIncludeBuffer
1197  *
1198  * PARAMETERS:  Pathname                - Name of the input binary file
1199  *              BufferName              - ACPI namepath of the buffer
1200  *
1201  * RETURN:      None.
1202  *
1203  * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents
1204  *              of the file are emitted into the buffer object as ascii
1205  *              hex data. From #includebuffer.
1206  *
1207  ******************************************************************************/
1208 
1209 static void
1210 PrDoIncludeBuffer (
1211     char                    *Pathname,
1212     char                    *BufferName)
1213 {
1214     char                    *FullPathname;
1215     FILE                    *BinaryBufferFile;
1216     UINT32                  i = 0;
1217     UINT8                   c;
1218 
1219 
1220     BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname);
1221     if (!BinaryBufferFile)
1222     {
1223         return;
1224     }
1225 
1226     /* Emit "Name (XXXX, Buffer() {" header */
1227 
1228     FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName);
1229 
1230     /* Dump the entire file in ascii hex format */
1231 
1232     while (fread (&c, 1, 1, BinaryBufferFile))
1233     {
1234         if (!(i % 8))
1235         {
1236             FlPrintFile (ASL_FILE_PREPROCESSOR, "\n   ", c);
1237         }
1238 
1239         FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c);
1240         i++;
1241     }
1242 
1243     DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
1244         "#includebuffer: read %u bytes from %s\n",
1245         Gbl_CurrentLineNumber, i, FullPathname);
1246 
1247     /* Close the Name() operator */
1248 
1249     FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName);
1250     fclose (BinaryBufferFile);
1251 }
1252