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