xref: /dflybsd-src/sys/contrib/dev/acpica/source/compiler/prscan.c (revision 3eec877432eb8056a5450dd96fad6f6abad016b9)
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 "aslcompiler.h"
47 #include "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             return (ASL_EOF);
923         }
924 
925         /* Update state machine as necessary */
926 
927         switch (AcpiGbl_LineScanState)
928         {
929         case PR_NORMAL_TEXT:
930 
931             /* Check for multi-line comment start */
932 
933             if ((PreviousChar == '/') && (c == '*'))
934             {
935                 AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT;
936             }
937 
938             /* Check for single-line comment start */
939 
940             else if ((PreviousChar == '/') && (c == '/'))
941             {
942                 AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT;
943             }
944 
945             /* Check for quoted string start */
946 
947             else if (PreviousChar == '"')
948             {
949                 AcpiGbl_LineScanState = PR_QUOTED_STRING;
950             }
951             break;
952 
953         case PR_QUOTED_STRING:
954 
955             if (PreviousChar == '"')
956             {
957                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
958             }
959             break;
960 
961         case PR_MULTI_LINE_COMMENT:
962 
963             /* Check for multi-line comment end */
964 
965             if ((PreviousChar == '*') && (c == '/'))
966             {
967                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
968             }
969             break;
970 
971         case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */
972         default:
973             break;
974         }
975 
976         /* Always copy the character into line buffer */
977 
978         Gbl_CurrentLineBuffer[i] = (char) c;
979         i++;
980 
981         /* Always exit on end-of-line */
982 
983         if (c == '\n')
984         {
985             /* Handle multi-line comments */
986 
987             if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT)
988             {
989                 return (ASL_IGNORE_LINE);
990             }
991 
992             /* End of single-line comment */
993 
994             if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT)
995             {
996                 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
997                 return (AE_OK);
998             }
999 
1000             /* Blank line */
1001 
1002             if (i == 1)
1003             {
1004                 return (ASL_IGNORE_LINE);
1005             }
1006 
1007             return (AE_OK);
1008         }
1009     }
1010 }
1011 
1012 
1013 /*******************************************************************************
1014  *
1015  * FUNCTION:    PrMatchDirective
1016  *
1017  * PARAMETERS:  Directive           - Pointer to directive name token
1018  *
1019  * RETURN:      Index into command array, -1 if not found
1020  *
1021  * DESCRIPTION: Lookup the incoming directive in the known directives table.
1022  *
1023  ******************************************************************************/
1024 
1025 static int
1026 PrMatchDirective (
1027     char                    *Directive)
1028 {
1029     int                     i;
1030 
1031 
1032     if (!Directive || Directive[0] == 0)
1033     {
1034         return (ASL_DIRECTIVE_NOT_FOUND);
1035     }
1036 
1037     for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
1038     {
1039         if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
1040         {
1041             return (i);
1042         }
1043     }
1044 
1045     return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
1046 }
1047 
1048 
1049 /*******************************************************************************
1050  *
1051  * FUNCTION:    PrPushDirective
1052  *
1053  * PARAMETERS:  Directive           - Encoded directive ID
1054  *              Argument            - String containing argument to the
1055  *                                    directive
1056  *
1057  * RETURN:      None
1058  *
1059  * DESCRIPTION: Push an item onto the directive stack. Used for processing
1060  *              nested #if/#else type conditional compilation directives.
1061  *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
1062  *              a block.
1063  *
1064  ******************************************************************************/
1065 
1066 static void
1067 PrPushDirective (
1068     int                     Directive,
1069     char                    *Argument)
1070 {
1071     DIRECTIVE_INFO          *Info;
1072 
1073 
1074     /* Allocate and populate a stack info item */
1075 
1076     Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
1077 
1078     Info->Next = Gbl_DirectiveStack;
1079     Info->Directive = Directive;
1080     Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
1081     strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
1082 
1083     DbgPrint (ASL_DEBUG_OUTPUT,
1084         "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
1085         Gbl_CurrentLineNumber, Gbl_IfDepth,
1086         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1087         Gbl_IfDepth * 4, " ",
1088         Gbl_DirectiveInfo[Directive].Name,
1089         Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1090 
1091     /* Push new item */
1092 
1093     Gbl_DirectiveStack = Info;
1094     Gbl_IfDepth++;
1095 }
1096 
1097 
1098 /*******************************************************************************
1099  *
1100  * FUNCTION:    PrPopDirective
1101  *
1102  * PARAMETERS:  None
1103  *
1104  * RETURN:      Status. Error if the stack is empty.
1105  *
1106  * DESCRIPTION: Pop an item off the directive stack. Used for processing
1107  *              nested #if/#else type conditional compilation directives.
1108  *              Specifically: Used on detection of #elif and #endif to remove
1109  *              the original #if/#ifdef/#ifndef from the stack and close
1110  *              the block.
1111  *
1112  ******************************************************************************/
1113 
1114 static ACPI_STATUS
1115 PrPopDirective (
1116     void)
1117 {
1118     DIRECTIVE_INFO          *Info;
1119 
1120 
1121     /* Check for empty stack */
1122 
1123     Info = Gbl_DirectiveStack;
1124     if (!Info)
1125     {
1126         return (AE_ERROR);
1127     }
1128 
1129     /* Pop one item, keep globals up-to-date */
1130 
1131     Gbl_IfDepth--;
1132     Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
1133     Gbl_DirectiveStack = Info->Next;
1134 
1135     DbgPrint (ASL_DEBUG_OUTPUT,
1136         "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
1137         Gbl_CurrentLineNumber, Gbl_IfDepth,
1138         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1139         Gbl_IfDepth * 4, " ",
1140         Gbl_DirectiveInfo[Info->Directive].Name,
1141         Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1142 
1143     ACPI_FREE (Info);
1144     return (AE_OK);
1145 }
1146 
1147 
1148 /*******************************************************************************
1149  *
1150  * FUNCTION:    PrDbgPrint
1151  *
1152  * PARAMETERS:  Action              - Action being performed
1153  *              DirectiveName       - Directive being processed
1154  *
1155  * RETURN:      None
1156  *
1157  * DESCRIPTION: Special debug print for directive processing.
1158  *
1159  ******************************************************************************/
1160 
1161 static void
1162 PrDbgPrint (
1163     char                    *Action,
1164     char                    *DirectiveName)
1165 {
1166 
1167     DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
1168         "%*s %s #%s, IfDepth %u\n",
1169         Gbl_CurrentLineNumber, Gbl_IfDepth,
1170         Gbl_IgnoringThisCodeBlock ? "I" : "E",
1171         Gbl_IfDepth * 4, " ",
1172         Action, DirectiveName, Gbl_IfDepth);
1173 }
1174 
1175 
1176 /*******************************************************************************
1177  *
1178  * FUNCTION:    PrDoIncludeFile
1179  *
1180  * PARAMETERS:  Pathname                - Name of the input file
1181  *
1182  * RETURN:      None.
1183  *
1184  * DESCRIPTION: Open an include file, from #include.
1185  *
1186  ******************************************************************************/
1187 
1188 static void
1189 PrDoIncludeFile (
1190     char                    *Pathname)
1191 {
1192     char                    *FullPathname;
1193 
1194 
1195     (void) PrOpenIncludeFile (Pathname, "r", &FullPathname);
1196 }
1197 
1198 
1199 /*******************************************************************************
1200  *
1201  * FUNCTION:    PrDoIncludeBuffer
1202  *
1203  * PARAMETERS:  Pathname                - Name of the input binary file
1204  *              BufferName              - ACPI namepath of the buffer
1205  *
1206  * RETURN:      None.
1207  *
1208  * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents
1209  *              of the file are emitted into the buffer object as ascii
1210  *              hex data. From #includebuffer.
1211  *
1212  ******************************************************************************/
1213 
1214 static void
1215 PrDoIncludeBuffer (
1216     char                    *Pathname,
1217     char                    *BufferName)
1218 {
1219     char                    *FullPathname;
1220     FILE                    *BinaryBufferFile;
1221     UINT32                  i = 0;
1222     UINT8                   c;
1223 
1224 
1225     BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname);
1226     if (!BinaryBufferFile)
1227     {
1228         return;
1229     }
1230 
1231     /* Emit "Name (XXXX, Buffer() {" header */
1232 
1233     FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName);
1234 
1235     /* Dump the entire file in ascii hex format */
1236 
1237     while (fread (&c, 1, 1, BinaryBufferFile))
1238     {
1239         if (!(i % 8))
1240         {
1241             FlPrintFile (ASL_FILE_PREPROCESSOR, "\n   ", c);
1242         }
1243 
1244         FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c);
1245         i++;
1246     }
1247 
1248     DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
1249         "#includebuffer: read %u bytes from %s\n",
1250         Gbl_CurrentLineNumber, i, FullPathname);
1251 
1252     /* Close the Name() operator */
1253 
1254     FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName);
1255     fclose (BinaryBufferFile);
1256 }
1257