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