Sync ACPICA with Intel's version 20160108.
[dragonfly.git] / sys / contrib / dev / acpica / source / compiler / prscan.c
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_WITHIN_COMMENT) ||
338             (Status == ASL_BLANK_LINE))
339         {
340             goto WriteEntireLine;
341         }
342
343         /* Need a copy of the input line for strok() */
344
345         strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
346         Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
347         OffsetAdjust = 0;
348
349         /* All preprocessor directives must begin with '#' */
350
351         if (Token && (*Token == '#'))
352         {
353             if (strlen (Token) == 1)
354             {
355                 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
356             }
357             else
358             {
359                 Token++;    /* Skip leading # */
360             }
361
362             /* Execute the directive, do not write line to output file */
363
364             PrDoDirective (Token, &Next);
365             continue;
366         }
367
368         /*
369          * If we are currently within the part of an IF/ELSE block that is
370          * FALSE, ignore the line and do not write it to the output file.
371          * This continues until an #else or #endif is encountered.
372          */
373         if (Gbl_IgnoringThisCodeBlock)
374         {
375             continue;
376         }
377
378         /* Match and replace all #defined names within this source line */
379
380         while (Token)
381         {
382             DefineInfo = PrMatchDefine (Token);
383             if (DefineInfo)
384             {
385                 if (DefineInfo->Body)
386                 {
387                     /* This is a macro */
388
389                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
390                         "Matched Macro: %s->%s\n",
391                         Gbl_CurrentLineNumber, DefineInfo->Identifier,
392                         DefineInfo->Replacement);
393
394                     PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
395                         DefineInfo, &Next);
396                 }
397                 else
398                 {
399                     ReplaceString = DefineInfo->Replacement;
400
401                     /* Replace the name in the original line buffer */
402
403                     TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
404                     PrReplaceData (
405                         &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
406                         ReplaceString, strlen (ReplaceString));
407
408                     /* Adjust for length difference between old and new name length */
409
410                     OffsetAdjust += strlen (ReplaceString) - strlen (Token);
411
412                     DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
413                         "Matched #define: %s->%s\n",
414                         Gbl_CurrentLineNumber, Token,
415                         *ReplaceString ? ReplaceString : "(NULL STRING)");
416                 }
417             }
418
419             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
420         }
421
422         Gbl_PreprocessorLineNumber++;
423
424
425 WriteEntireLine:
426         /*
427          * Now we can write the possibly modified source line to the
428          * preprocessor file(s).
429          */
430         FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
431             strlen (Gbl_CurrentLineBuffer));
432     }
433 }
434
435
436 /*******************************************************************************
437  *
438  * FUNCTION:    PrDoDirective
439  *
440  * PARAMETERS:  Directive               - Pointer to directive name token
441  *              Next                    - "Next" buffer from GetNextToken
442  *
443  * RETURN:      None.
444  *
445  * DESCRIPTION: Main processing for all preprocessor directives
446  *
447  ******************************************************************************/
448
449 static void
450 PrDoDirective (
451     char                    *DirectiveToken,
452     char                    **Next)
453 {
454     char                    *Token = Gbl_MainTokenBuffer;
455     char                    *Token2 = NULL;
456     char                    *End;
457     UINT64                  Value;
458     ACPI_SIZE               TokenOffset;
459     int                     Directive;
460     ACPI_STATUS             Status;
461
462
463     if (!DirectiveToken)
464     {
465         goto SyntaxError;
466     }
467
468     Directive = PrMatchDirective (DirectiveToken);
469     if (Directive == ASL_DIRECTIVE_NOT_FOUND)
470     {
471         PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
472             THIS_TOKEN_OFFSET (DirectiveToken));
473
474         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
475             "#%s: Unknown directive\n",
476             Gbl_CurrentLineNumber, DirectiveToken);
477         return;
478     }
479
480     /*
481      * Emit a line directive into the preprocessor file (.pre) after
482      * every matched directive. This is passed through to the compiler
483      * so that error/warning messages are kept in sync with the
484      * original source file.
485      */
486     FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\" // #%s\n",
487         Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename,
488         Gbl_DirectiveInfo[Directive].Name);
489
490     /*
491      * If we are currently ignoring this block and we encounter a #else or
492      * #elif, we must ignore their blocks also if the parent block is also
493      * being ignored.
494      */
495     if (Gbl_IgnoringThisCodeBlock)
496     {
497         switch (Directive)
498         {
499         case PR_DIRECTIVE_ELSE:
500         case PR_DIRECTIVE_ELIF:
501
502             if (Gbl_DirectiveStack &&
503                 Gbl_DirectiveStack->IgnoringThisCodeBlock)
504             {
505                 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
506                 return;
507             }
508             break;
509
510         default:
511             break;
512         }
513     }
514
515     /*
516      * Need to always check for #else, #elif, #endif regardless of
517      * whether we are ignoring the current code block, since these
518      * are conditional code block terminators.
519      */
520     switch (Directive)
521     {
522     case PR_DIRECTIVE_ELSE:
523
524         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
525         PrDbgPrint ("Executing", "else block");
526         return;
527
528     case PR_DIRECTIVE_ELIF:
529
530         Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
531         Directive = PR_DIRECTIVE_IF;
532
533         if (Gbl_IgnoringThisCodeBlock == TRUE)
534         {
535             /* Not executing the ELSE part -- all done here */
536             PrDbgPrint ("Ignoring", "elif block");
537             return;
538         }
539
540         /*
541          * After this, we will execute the IF part further below.
542          * First, however, pop off the original #if directive.
543          */
544         if (ACPI_FAILURE (PrPopDirective ()))
545         {
546             PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
547                 THIS_TOKEN_OFFSET (DirectiveToken));
548         }
549
550         PrDbgPrint ("Executing", "elif block");
551         break;
552
553     case PR_DIRECTIVE_ENDIF:
554
555         PrDbgPrint ("Executing", "endif");
556
557         /* Pop the owning #if/#ifdef/#ifndef */
558
559         if (ACPI_FAILURE (PrPopDirective ()))
560         {
561             PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
562                 THIS_TOKEN_OFFSET (DirectiveToken));
563         }
564         return;
565
566     default:
567         break;
568     }
569
570     /* Most directives have at least one argument */
571
572     if (Gbl_DirectiveInfo[Directive].ArgCount >= 1)
573     {
574         Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
575         if (!Token)
576         {
577             goto SyntaxError;
578         }
579     }
580
581     if (Gbl_DirectiveInfo[Directive].ArgCount >= 2)
582     {
583         Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
584         if (!Token2)
585         {
586             goto SyntaxError;
587         }
588     }
589
590     /*
591      * At this point, if we are ignoring the current code block,
592      * do not process any more directives (i.e., ignore them also.)
593      * For "if" style directives, open/push a new block anyway. We
594      * must do this to keep track of #endif directives
595      */
596     if (Gbl_IgnoringThisCodeBlock)
597     {
598         switch (Directive)
599         {
600         case PR_DIRECTIVE_IF:
601         case PR_DIRECTIVE_IFDEF:
602         case PR_DIRECTIVE_IFNDEF:
603
604             PrPushDirective (Directive, Token);
605             PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
606             break;
607
608         default:
609             break;
610         }
611
612         return;
613     }
614
615     /*
616      * Execute the directive
617      */
618     PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
619
620     switch (Directive)
621     {
622     case PR_DIRECTIVE_IF:
623
624         TokenOffset = Token - Gbl_MainTokenBuffer;
625
626         /* Need to expand #define macros in the expression string first */
627
628         Status = PrResolveIntegerExpression (
629             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
630         if (ACPI_FAILURE (Status))
631         {
632             return;
633         }
634
635         PrPushDirective (Directive, Token);
636         if (!Value)
637         {
638             Gbl_IgnoringThisCodeBlock = TRUE;
639         }
640
641         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
642             "Resolved #if: %8.8X%8.8X %s\n",
643             Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
644             Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
645         break;
646
647     case PR_DIRECTIVE_IFDEF:
648
649         PrPushDirective (Directive, Token);
650         if (!PrMatchDefine (Token))
651         {
652             Gbl_IgnoringThisCodeBlock = TRUE;
653         }
654
655         PrDbgPrint ("Evaluated", "ifdef");
656         break;
657
658     case PR_DIRECTIVE_IFNDEF:
659
660         PrPushDirective (Directive, Token);
661         if (PrMatchDefine (Token))
662         {
663             Gbl_IgnoringThisCodeBlock = TRUE;
664         }
665
666         PrDbgPrint ("Evaluated", "ifndef");
667         break;
668
669     case PR_DIRECTIVE_DEFINE:
670         /*
671          * By definition, if first char after the name is a paren,
672          * this is a function macro.
673          */
674         TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
675         if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
676         {
677 #ifndef MACROS_SUPPORTED
678             AcpiOsPrintf (
679                 "%s ERROR - line %u: #define macros are not supported yet\n",
680                 Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber);
681             exit(1);
682 #else
683             PrAddMacro (Token, Next);
684 #endif
685         }
686         else
687         {
688             /* Use the remainder of the line for the #define */
689
690             Token2 = *Next;
691             if (Token2)
692             {
693                 while ((*Token2 == ' ') || (*Token2 == '\t'))
694                 {
695                     Token2++;
696                 }
697
698                 End = Token2;
699                 while (*End != '\n')
700                 {
701                     End++;
702                 }
703
704                 *End = 0;
705             }
706             else
707             {
708                 Token2 = "";
709             }
710 #if 0
711             Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
712             if (!Token2)
713             {
714                 Token2 = "";
715             }
716 #endif
717             DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
718                 "New #define: %s->%s\n",
719                 Gbl_LogicalLineNumber, Token, Token2);
720
721             PrAddDefine (Token, Token2, FALSE);
722         }
723         break;
724
725     case PR_DIRECTIVE_ERROR:
726
727         /* Note: No macro expansion */
728
729         PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
730             THIS_TOKEN_OFFSET (Token));
731
732         Gbl_SourceLine = 0;
733         Gbl_NextError = Gbl_ErrorLog;
734         CmCleanupAndExit ();
735         exit(1);
736
737     case PR_DIRECTIVE_INCLUDE:
738
739         Token = PrGetNextToken (NULL, " \"<>", Next);
740         if (!Token)
741         {
742             goto SyntaxError;
743         }
744
745         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
746             "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
747             Token, Gbl_CurrentLineNumber);
748
749         PrDoIncludeFile (Token);
750         break;
751
752     case PR_DIRECTIVE_INCLUDEBUFFER:
753
754         Token = PrGetNextToken (NULL, " \"<>", Next);
755         if (!Token)
756         {
757             goto SyntaxError;
758         }
759
760         Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
761         if (!Token2)
762         {
763             goto SyntaxError;
764         }
765
766         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
767             "Start #includebuffer input from file \"%s\", buffer name %s\n",
768             Gbl_CurrentLineNumber, Token, Token2);
769
770         PrDoIncludeBuffer (Token, Token2);
771         break;
772
773     case PR_DIRECTIVE_LINE:
774
775         TokenOffset = Token - Gbl_MainTokenBuffer;
776
777         Status = PrResolveIntegerExpression (
778             &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
779         if (ACPI_FAILURE (Status))
780         {
781             return;
782         }
783
784         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
785             "User #line invocation %s\n", Gbl_CurrentLineNumber,
786             Token);
787
788         Gbl_CurrentLineNumber = (UINT32) Value;
789
790         /* Emit #line into the preprocessor file */
791
792         FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
793             Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
794         break;
795
796     case PR_DIRECTIVE_PRAGMA:
797
798         if (!strcmp (Token, "disable"))
799         {
800             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
801             if (!Token)
802             {
803                 goto SyntaxError;
804             }
805
806             TokenOffset = Token - Gbl_MainTokenBuffer;
807             AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
808         }
809         else if (!strcmp (Token, "message"))
810         {
811             Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
812             if (!Token)
813             {
814                 goto SyntaxError;
815             }
816
817             TokenOffset = Token - Gbl_MainTokenBuffer;
818             AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
819         }
820         else
821         {
822             PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
823                 THIS_TOKEN_OFFSET (Token));
824             return;
825         }
826
827         break;
828
829     case PR_DIRECTIVE_UNDEF:
830
831         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
832             "#undef: %s\n", Gbl_CurrentLineNumber, Token);
833
834         PrRemoveDefine (Token);
835         break;
836
837     case PR_DIRECTIVE_WARNING:
838
839         PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
840             THIS_TOKEN_OFFSET (Token));
841
842         Gbl_SourceLine = 0;
843         Gbl_NextError = Gbl_ErrorLog;
844         break;
845
846     default:
847
848         /* Should never get here */
849         DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
850             "Unrecognized directive: %u\n",
851             Gbl_CurrentLineNumber, Directive);
852         break;
853     }
854
855     return;
856
857 SyntaxError:
858
859     PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
860         THIS_TOKEN_OFFSET (DirectiveToken));
861     return;
862 }
863
864
865 /*******************************************************************************
866  *
867  * FUNCTION:    PrGetNextLine, PrGetNextLineInit
868  *
869  * PARAMETERS:  Handle              - Open file handle for the source file
870  *
871  * RETURN:      Status of the GetLine operation:
872  *              AE_OK               - Normal line, OK status
873  *              ASL_WITHIN_COMMENT  - Line is part of a multi-line 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_WITHIN_COMMENT);
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_BLANK_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 }