xref: /freebsd/sys/contrib/dev/acpica/compiler/prscan.c (revision 3fc36ee018bb836bd1796067cf4ef8683f166ebc)
1 /******************************************************************************
2  *
3  * Module Name: prscan - Preprocessor start-up and file scan module
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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_IGNORE_LINE)
338         {
339             goto WriteEntireLine;
340         }
341 
342         /* Need a copy of the input line for strok() */
343 
344         strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
345         Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
346         OffsetAdjust = 0;
347 
348         /* All preprocessor directives must begin with '#' */
349 
350         if (Token && (*Token == '#'))
351         {
352             if (strlen (Token) == 1)
353             {
354                 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
355             }
356             else
357             {
358                 Token++;    /* Skip leading # */
359             }
360 
361             /* Execute the directive, do not write line to output file */
362 
363             PrDoDirective (Token, &Next);
364             continue;
365         }
366 
367         /*
368          * If we are currently within the part of an IF/ELSE block that is
369          * FALSE, ignore the line and do not write it to the output file.
370          * This continues until an #else or #endif is encountered.
371          */
372         if (Gbl_IgnoringThisCodeBlock)
373         {
374             continue;
375         }
376 
377         /* Match and replace all #defined names within this source line */
378 
379         while (Token)
380         {
381             DefineInfo = PrMatchDefine (Token);
382             if (DefineInfo)
383             {
384                 if (DefineInfo->Body)
385                 {
386                     /* This is a macro */
387 
388                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
389                         "Matched Macro: %s->%s\n",
390                         Gbl_CurrentLineNumber, DefineInfo->Identifier,
391                         DefineInfo->Replacement);
392 
393                     PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
394                         DefineInfo, &Next);
395                 }
396                 else
397                 {
398                     ReplaceString = DefineInfo->Replacement;
399 
400                     /* Replace the name in the original line buffer */
401 
402                     TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
403                     PrReplaceData (
404                         &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
405                         ReplaceString, strlen (ReplaceString));
406 
407                     /* Adjust for length difference between old and new name length */
408 
409                     OffsetAdjust += strlen (ReplaceString) - strlen (Token);
410 
411                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
412                         "Matched #define: %s->%s\n",
413                         Gbl_CurrentLineNumber, Token,
414                         *ReplaceString ? ReplaceString : "(NULL STRING)");
415                 }
416             }
417 
418             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
419         }
420 
421         Gbl_PreprocessorLineNumber++;
422 
423 
424 WriteEntireLine:
425         /*
426          * Now we can write the possibly modified source line to the
427          * preprocessor file(s).
428          */
429         FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
430             strlen (Gbl_CurrentLineBuffer));
431     }
432 }
433 
434 
435 /*******************************************************************************
436  *
437  * FUNCTION:    PrDoDirective
438  *
439  * PARAMETERS:  Directive               - Pointer to directive name token
440  *              Next                    - "Next" buffer from GetNextToken
441  *
442  * RETURN:      None.
443  *
444  * DESCRIPTION: Main processing for all preprocessor directives
445  *
446  ******************************************************************************/
447 
448 static void
449 PrDoDirective (
450     char                    *DirectiveToken,
451     char                    **Next)
452 {
453     char                    *Token = Gbl_MainTokenBuffer;
454     char                    *Token2 = NULL;
455     char                    *End;
456     UINT64                  Value;
457     ACPI_SIZE               TokenOffset;
458     int                     Directive;
459     ACPI_STATUS             Status;
460 
461 
462     if (!DirectiveToken)
463     {
464         goto SyntaxError;
465     }
466 
467     Directive = PrMatchDirective (DirectiveToken);
468     if (Directive == ASL_DIRECTIVE_NOT_FOUND)
469     {
470         PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
471             THIS_TOKEN_OFFSET (DirectiveToken));
472 
473         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
474             "#%s: Unknown directive\n",
475             Gbl_CurrentLineNumber, DirectiveToken);
476         return;
477     }
478 
479     /*
480      * Emit a line directive into the preprocessor file (.pre) after
481      * every matched directive. This is passed through to the compiler
482      * so that error/warning messages are kept in sync with the
483      * original source file.
484      */
485     FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\" // #%s\n",
486         Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename,
487         Gbl_DirectiveInfo[Directive].Name);
488 
489     /*
490      * If we are currently ignoring this block and we encounter a #else or
491      * #elif, we must ignore their blocks also if the parent block is also
492      * being ignored.
493      */
494     if (Gbl_IgnoringThisCodeBlock)
495     {
496         switch (Directive)
497         {
498         case PR_DIRECTIVE_ELSE:
499         case PR_DIRECTIVE_ELIF:
500 
501             if (Gbl_DirectiveStack &&
502                 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 (
678                 "%s ERROR - line %u: #define macros are not supported yet\n",
679                 Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber);
680             exit(1);
681 #else
682             PrAddMacro (Token, Next);
683 #endif
684         }
685         else
686         {
687             /* Use the remainder of the line for the #define */
688 
689             Token2 = *Next;
690             if (Token2)
691             {
692                 while ((*Token2 == ' ') || (*Token2 == '\t'))
693                 {
694                     Token2++;
695                 }
696 
697                 End = Token2;
698                 while (*End != '\n')
699                 {
700                     End++;
701                 }
702 
703                 *End = 0;
704             }
705             else
706             {
707                 Token2 = "";
708             }
709 #if 0
710             Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
711             if (!Token2)
712             {
713                 Token2 = "";
714             }
715 #endif
716             DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
717                 "New #define: %s->%s\n",
718                 Gbl_LogicalLineNumber, Token, Token2);
719 
720             PrAddDefine (Token, Token2, FALSE);
721         }
722         break;
723 
724     case PR_DIRECTIVE_ERROR:
725 
726         /* Note: No macro expansion */
727 
728         PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
729             THIS_TOKEN_OFFSET (Token));
730 
731         Gbl_SourceLine = 0;
732         Gbl_NextError = Gbl_ErrorLog;
733         CmCleanupAndExit ();
734         exit(1);
735 
736     case PR_DIRECTIVE_INCLUDE:
737 
738         Token = PrGetNextToken (NULL, " \"<>", Next);
739         if (!Token)
740         {
741             goto SyntaxError;
742         }
743 
744         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
745             "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
746             Token, Gbl_CurrentLineNumber);
747 
748         PrDoIncludeFile (Token);
749         break;
750 
751     case PR_DIRECTIVE_INCLUDEBUFFER:
752 
753         Token = PrGetNextToken (NULL, " \"<>", Next);
754         if (!Token)
755         {
756             goto SyntaxError;
757         }
758 
759         Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
760         if (!Token2)
761         {
762             goto SyntaxError;
763         }
764 
765         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
766             "Start #includebuffer input from file \"%s\", buffer name %s\n",
767             Gbl_CurrentLineNumber, Token, Token2);
768 
769         PrDoIncludeBuffer (Token, Token2);
770         break;
771 
772     case PR_DIRECTIVE_LINE:
773 
774         TokenOffset = Token - Gbl_MainTokenBuffer;
775 
776         Status = PrResolveIntegerExpression (
777             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
778         if (ACPI_FAILURE (Status))
779         {
780             return;
781         }
782 
783         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
784             "User #line invocation %s\n", Gbl_CurrentLineNumber,
785             Token);
786 
787         Gbl_CurrentLineNumber = (UINT32) Value;
788 
789         /* Emit #line into the preprocessor file */
790 
791         FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
792             Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
793         break;
794 
795     case PR_DIRECTIVE_PRAGMA:
796 
797         if (!strcmp (Token, "disable"))
798         {
799             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
800             if (!Token)
801             {
802                 goto SyntaxError;
803             }
804 
805             TokenOffset = Token - Gbl_MainTokenBuffer;
806             AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
807         }
808         else if (!strcmp (Token, "message"))
809         {
810             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
811             if (!Token)
812             {
813                 goto SyntaxError;
814             }
815 
816             TokenOffset = Token - Gbl_MainTokenBuffer;
817             AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
818         }
819         else
820         {
821             PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
822                 THIS_TOKEN_OFFSET (Token));
823             return;
824         }
825 
826         break;
827 
828     case PR_DIRECTIVE_UNDEF:
829 
830         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
831             "#undef: %s\n", Gbl_CurrentLineNumber, Token);
832 
833         PrRemoveDefine (Token);
834         break;
835 
836     case PR_DIRECTIVE_WARNING:
837 
838         PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
839             THIS_TOKEN_OFFSET (Token));
840 
841         Gbl_SourceLine = 0;
842         Gbl_NextError = Gbl_ErrorLog;
843         break;
844 
845     default:
846 
847         /* Should never get here */
848         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
849             "Unrecognized directive: %u\n",
850             Gbl_CurrentLineNumber, Directive);
851         break;
852     }
853 
854     return;
855 
856 SyntaxError:
857 
858     PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
859         THIS_TOKEN_OFFSET (DirectiveToken));
860     return;
861 }
862 
863 
864 /*******************************************************************************
865  *
866  * FUNCTION:    PrGetNextLine, PrGetNextLineInit
867  *
868  * PARAMETERS:  Handle              - Open file handle for the source file
869  *
870  * RETURN:      Status of the GetLine operation:
871  *              AE_OK               - Normal line, OK status
872  *              ASL_IGNORE_LINE     - Line is blank or part of a multi-line
873  *                                      comment
874  *              ASL_EOF             - End-of-file reached
875  *
876  * DESCRIPTION: Get the next text line from the input file. Does not strip
877  *              comments.
878  *
879  ******************************************************************************/
880 
881 #define PR_NORMAL_TEXT          0
882 #define PR_MULTI_LINE_COMMENT   1
883 #define PR_SINGLE_LINE_COMMENT  2
884 #define PR_QUOTED_STRING        3
885 
886 static UINT8                    AcpiGbl_LineScanState = PR_NORMAL_TEXT;
887 
888 static void
889 PrGetNextLineInit (
890     void)
891 {
892     AcpiGbl_LineScanState = 0;
893 }
894 
895 static UINT32
896 PrGetNextLine (
897     FILE                    *Handle)
898 {
899     UINT32                  i;
900     int                     c = 0;
901     int                     PreviousChar;
902 
903 
904     /* Always clear the global line buffer */
905 
906     memset (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize);
907     for (i = 0; ;)
908     {
909         /*
910          * If line is too long, expand the line buffers. Also increases
911          * Gbl_LineBufferSize.
912          */
913         if (i >= Gbl_LineBufferSize)
914         {
915             UtExpandLineBuffers ();
916         }
917 
918         PreviousChar = c;
919         c = getc (Handle);
920         if (c == EOF)
921         {
922             /*
923              * On EOF: If there is anything in the line buffer, terminate
924              * it with a newline, and catch the EOF on the next call
925              * to this function.
926              */
927             if (i > 0)
928             {
929                 Gbl_CurrentLineBuffer[i] = '\n';
930                 return (AE_OK);
931             }
932 
933             return (ASL_EOF);
934         }
935 
936         /* Update state machine as necessary */
937 
938         switch (AcpiGbl_LineScanState)
939         {
940         case PR_NORMAL_TEXT:
941 
942             /* Check for multi-line comment start */
943 
944             if ((PreviousChar == '/') && (c == '*'))
945             {
946                 AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT;
947             }
948 
949             /* Check for single-line comment start */
950 
951             else if ((PreviousChar == '/') && (c == '/'))
952             {
953                 AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT;
954             }
955 
956             /* Check for quoted string start */
957 
958             else if (PreviousChar == '"')
959             {
960                 AcpiGbl_LineScanState = PR_QUOTED_STRING;
961             }
962             break;
963 
964         case PR_QUOTED_STRING:
965 
966             if (PreviousChar == '"')
967             {
968                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
969             }
970             break;
971 
972         case PR_MULTI_LINE_COMMENT:
973 
974             /* Check for multi-line comment end */
975 
976             if ((PreviousChar == '*') && (c == '/'))
977             {
978                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
979             }
980             break;
981 
982         case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */
983         default:
984             break;
985         }
986 
987         /* Always copy the character into line buffer */
988 
989         Gbl_CurrentLineBuffer[i] = (char) c;
990         i++;
991 
992         /* Always exit on end-of-line */
993 
994         if (c == '\n')
995         {
996             /* Handle multi-line comments */
997 
998             if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT)
999             {
1000                 return (ASL_IGNORE_LINE);
1001             }
1002 
1003             /* End of single-line comment */
1004 
1005             if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT)
1006             {
1007                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
1008                 return (AE_OK);
1009             }
1010 
1011             /* Blank line */
1012 
1013             if (i == 1)
1014             {
1015                 return (ASL_IGNORE_LINE);
1016             }
1017 
1018             return (AE_OK);
1019         }
1020     }
1021 }
1022 
1023 
1024 /*******************************************************************************
1025  *
1026  * FUNCTION:    PrMatchDirective
1027  *
1028  * PARAMETERS:  Directive           - Pointer to directive name token
1029  *
1030  * RETURN:      Index into command array, -1 if not found
1031  *
1032  * DESCRIPTION: Lookup the incoming directive in the known directives table.
1033  *
1034  ******************************************************************************/
1035 
1036 static int
1037 PrMatchDirective (
1038     char                    *Directive)
1039 {
1040     int                     i;
1041 
1042 
1043     if (!Directive || Directive[0] == 0)
1044     {
1045         return (ASL_DIRECTIVE_NOT_FOUND);
1046     }
1047 
1048     for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
1049     {
1050         if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
1051         {
1052             return (i);
1053         }
1054     }
1055 
1056     return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
1057 }
1058 
1059 
1060 /*******************************************************************************
1061  *
1062  * FUNCTION:    PrPushDirective
1063  *
1064  * PARAMETERS:  Directive           - Encoded directive ID
1065  *              Argument            - String containing argument to the
1066  *                                    directive
1067  *
1068  * RETURN:      None
1069  *
1070  * DESCRIPTION: Push an item onto the directive stack. Used for processing
1071  *              nested #if/#else type conditional compilation directives.
1072  *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
1073  *              a block.
1074  *
1075  ******************************************************************************/
1076 
1077 static void
1078 PrPushDirective (
1079     int                     Directive,
1080     char                    *Argument)
1081 {
1082     DIRECTIVE_INFO          *Info;
1083 
1084 
1085     /* Allocate and populate a stack info item */
1086 
1087     Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
1088 
1089     Info->Next = Gbl_DirectiveStack;
1090     Info->Directive = Directive;
1091     Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
1092     strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
1093 
1094     DbgPrint (ASL_DEBUG_OUTPUT,
1095         "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
1096         Gbl_CurrentLineNumber, Gbl_IfDepth,
1097         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1098         Gbl_IfDepth * 4, " ",
1099         Gbl_DirectiveInfo[Directive].Name,
1100         Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1101 
1102     /* Push new item */
1103 
1104     Gbl_DirectiveStack = Info;
1105     Gbl_IfDepth++;
1106 }
1107 
1108 
1109 /*******************************************************************************
1110  *
1111  * FUNCTION:    PrPopDirective
1112  *
1113  * PARAMETERS:  None
1114  *
1115  * RETURN:      Status. Error if the stack is empty.
1116  *
1117  * DESCRIPTION: Pop an item off the directive stack. Used for processing
1118  *              nested #if/#else type conditional compilation directives.
1119  *              Specifically: Used on detection of #elif and #endif to remove
1120  *              the original #if/#ifdef/#ifndef from the stack and close
1121  *              the block.
1122  *
1123  ******************************************************************************/
1124 
1125 static ACPI_STATUS
1126 PrPopDirective (
1127     void)
1128 {
1129     DIRECTIVE_INFO          *Info;
1130 
1131 
1132     /* Check for empty stack */
1133 
1134     Info = Gbl_DirectiveStack;
1135     if (!Info)
1136     {
1137         return (AE_ERROR);
1138     }
1139 
1140     /* Pop one item, keep globals up-to-date */
1141 
1142     Gbl_IfDepth--;
1143     Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
1144     Gbl_DirectiveStack = Info->Next;
1145 
1146     DbgPrint (ASL_DEBUG_OUTPUT,
1147         "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
1148         Gbl_CurrentLineNumber, Gbl_IfDepth,
1149         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1150         Gbl_IfDepth * 4, " ",
1151         Gbl_DirectiveInfo[Info->Directive].Name,
1152         Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1153 
1154     ACPI_FREE (Info);
1155     return (AE_OK);
1156 }
1157 
1158 
1159 /*******************************************************************************
1160  *
1161  * FUNCTION:    PrDbgPrint
1162  *
1163  * PARAMETERS:  Action              - Action being performed
1164  *              DirectiveName       - Directive being processed
1165  *
1166  * RETURN:      None
1167  *
1168  * DESCRIPTION: Special debug print for directive processing.
1169  *
1170  ******************************************************************************/
1171 
1172 static void
1173 PrDbgPrint (
1174     char                    *Action,
1175     char                    *DirectiveName)
1176 {
1177 
1178     DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
1179         "%*s %s #%s, IfDepth %u\n",
1180         Gbl_CurrentLineNumber, Gbl_IfDepth,
1181         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1182         Gbl_IfDepth * 4, " ",
1183         Action, DirectiveName, Gbl_IfDepth);
1184 }
1185 
1186 
1187 /*******************************************************************************
1188  *
1189  * FUNCTION:    PrDoIncludeFile
1190  *
1191  * PARAMETERS:  Pathname                - Name of the input file
1192  *
1193  * RETURN:      None.
1194  *
1195  * DESCRIPTION: Open an include file, from #include.
1196  *
1197  ******************************************************************************/
1198 
1199 static void
1200 PrDoIncludeFile (
1201     char                    *Pathname)
1202 {
1203     char                    *FullPathname;
1204 
1205 
1206     (void) PrOpenIncludeFile (Pathname, "r", &FullPathname);
1207 }
1208 
1209 
1210 /*******************************************************************************
1211  *
1212  * FUNCTION:    PrDoIncludeBuffer
1213  *
1214  * PARAMETERS:  Pathname                - Name of the input binary file
1215  *              BufferName              - ACPI namepath of the buffer
1216  *
1217  * RETURN:      None.
1218  *
1219  * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents
1220  *              of the file are emitted into the buffer object as ascii
1221  *              hex data. From #includebuffer.
1222  *
1223  ******************************************************************************/
1224 
1225 static void
1226 PrDoIncludeBuffer (
1227     char                    *Pathname,
1228     char                    *BufferName)
1229 {
1230     char                    *FullPathname;
1231     FILE                    *BinaryBufferFile;
1232     UINT32                  i = 0;
1233     UINT8                   c;
1234 
1235 
1236     BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname);
1237     if (!BinaryBufferFile)
1238     {
1239         return;
1240     }
1241 
1242     /* Emit "Name (XXXX, Buffer() {" header */
1243 
1244     FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName);
1245 
1246     /* Dump the entire file in ascii hex format */
1247 
1248     while (fread (&c, 1, 1, BinaryBufferFile))
1249     {
1250         if (!(i % 8))
1251         {
1252             FlPrintFile (ASL_FILE_PREPROCESSOR, "\n   ", c);
1253         }
1254 
1255         FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c);
1256         i++;
1257     }
1258 
1259     DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
1260         "#includebuffer: read %u bytes from %s\n",
1261         Gbl_CurrentLineNumber, i, FullPathname);
1262 
1263     /* Close the Name() operator */
1264 
1265     FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName);
1266     fclose (BinaryBufferFile);
1267 }
1268