prscan.c revision 306536
1/******************************************************************************
2 *
3 * Module Name: prscan - Preprocessor start-up and file scan module
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#define _DECLARE_PR_GLOBALS
45
46#include <contrib/dev/acpica/compiler/aslcompiler.h>
47#include <contrib/dev/acpica/compiler/dtcompiler.h>
48
49/*
50 * TBDs:
51 *
52 * No nested macros, maybe never
53 * Implement ASL "Include" as well as "#include" here?
54 */
55#define _COMPONENT          ASL_PREPROCESSOR
56        ACPI_MODULE_NAME    ("prscan")
57
58
59/* Local prototypes */
60
61static void
62PrPreprocessInputFile (
63    void);
64
65static void
66PrDoDirective (
67    char                    *DirectiveToken,
68    char                    **Next);
69
70static void
71PrGetNextLineInit (
72    void);
73
74static UINT32
75PrGetNextLine (
76    FILE                    *Handle);
77
78static int
79PrMatchDirective (
80    char                    *Directive);
81
82static void
83PrPushDirective (
84    int                     Directive,
85    char                    *Argument);
86
87static ACPI_STATUS
88PrPopDirective (
89    void);
90
91static void
92PrDbgPrint (
93    char                    *Action,
94    char                    *DirectiveName);
95
96static void
97PrDoIncludeBuffer (
98    char                    *Pathname,
99    char                    *BufferName);
100
101static void
102PrDoIncludeFile (
103    char                    *Pathname);
104
105
106/*
107 * Supported preprocessor directives
108 * Each entry is of the form "Name, ArgumentCount"
109 */
110static 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
131enum 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
164void
165PrInitializePreprocessor (
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
189void
190PrInitializeGlobals (
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
222void
223PrTerminatePreprocessor (
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
259void
260PrDoPreprocess (
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
315static void
316PrPreprocessInputFile (
317    void)
318{
319    UINT32                  Status;
320    char                    *Token;
321    char                    *ReplaceString;
322    PR_DEFINE_INFO          *DefineInfo;
323    ACPI_SIZE               TokenOffset;
324    char                    *Next;
325    int                     OffsetAdjust;
326
327
328    PrGetNextLineInit ();
329
330    /* Scan source line-by-line and process directives. Then write the .i file */
331
332    while ((Status = PrGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF)
333    {
334        Gbl_CurrentLineNumber++;
335        Gbl_LogicalLineNumber++;
336
337        if (Status == ASL_IGNORE_LINE)
338        {
339            goto WriteEntireLine;
340        }
341
342        /* Need a copy of the input line for strok() */
343
344        strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
345        Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
346        OffsetAdjust = 0;
347
348        /* All preprocessor directives must begin with '#' */
349
350        if (Token && (*Token == '#'))
351        {
352            if (strlen (Token) == 1)
353            {
354                Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
355            }
356            else
357            {
358                Token++;    /* Skip leading # */
359            }
360
361            /* Execute the directive, do not write line to output file */
362
363            PrDoDirective (Token, &Next);
364            continue;
365        }
366
367        /*
368         * If we are currently within the part of an IF/ELSE block that is
369         * FALSE, ignore the line and do not write it to the output file.
370         * This continues until an #else or #endif is encountered.
371         */
372        if (Gbl_IgnoringThisCodeBlock)
373        {
374            continue;
375        }
376
377        /* Match and replace all #defined names within this source line */
378
379        while (Token)
380        {
381            DefineInfo = PrMatchDefine (Token);
382            if (DefineInfo)
383            {
384                if (DefineInfo->Body)
385                {
386                    /* This is a macro */
387
388                    DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
389                        "Matched Macro: %s->%s\n",
390                        Gbl_CurrentLineNumber, DefineInfo->Identifier,
391                        DefineInfo->Replacement);
392
393                    PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
394                        DefineInfo, &Next);
395                }
396                else
397                {
398                    ReplaceString = DefineInfo->Replacement;
399
400                    /* Replace the name in the original line buffer */
401
402                    TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
403                    PrReplaceData (
404                        &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
405                        ReplaceString, strlen (ReplaceString));
406
407                    /* Adjust for length difference between old and new name length */
408
409                    OffsetAdjust += strlen (ReplaceString) - strlen (Token);
410
411                    DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
412                        "Matched #define: %s->%s\n",
413                        Gbl_CurrentLineNumber, Token,
414                        *ReplaceString ? ReplaceString : "(NULL STRING)");
415                }
416            }
417
418            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
419        }
420
421        Gbl_PreprocessorLineNumber++;
422
423
424WriteEntireLine:
425        /*
426         * Now we can write the possibly modified source line to the
427         * preprocessor file(s).
428         */
429        FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
430            strlen (Gbl_CurrentLineBuffer));
431    }
432}
433
434
435/*******************************************************************************
436 *
437 * FUNCTION:    PrDoDirective
438 *
439 * PARAMETERS:  Directive               - Pointer to directive name token
440 *              Next                    - "Next" buffer from GetNextToken
441 *
442 * RETURN:      None.
443 *
444 * DESCRIPTION: Main processing for all preprocessor directives
445 *
446 ******************************************************************************/
447
448static void
449PrDoDirective (
450    char                    *DirectiveToken,
451    char                    **Next)
452{
453    char                    *Token = Gbl_MainTokenBuffer;
454    char                    *Token2 = NULL;
455    char                    *End;
456    UINT64                  Value;
457    ACPI_SIZE               TokenOffset;
458    int                     Directive;
459    ACPI_STATUS             Status;
460
461
462    if (!DirectiveToken)
463    {
464        goto SyntaxError;
465    }
466
467    Directive = PrMatchDirective (DirectiveToken);
468    if (Directive == ASL_DIRECTIVE_NOT_FOUND)
469    {
470        PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
471            THIS_TOKEN_OFFSET (DirectiveToken));
472
473        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
474            "#%s: Unknown directive\n",
475            Gbl_CurrentLineNumber, DirectiveToken);
476        return;
477    }
478
479    /*
480     * Emit a line directive into the preprocessor file (.pre) after
481     * every matched directive. This is passed through to the compiler
482     * so that error/warning messages are kept in sync with the
483     * original source file.
484     */
485    FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\" // #%s\n",
486        Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename,
487        Gbl_DirectiveInfo[Directive].Name);
488
489    /*
490     * If we are currently ignoring this block and we encounter a #else or
491     * #elif, we must ignore their blocks also if the parent block is also
492     * being ignored.
493     */
494    if (Gbl_IgnoringThisCodeBlock)
495    {
496        switch (Directive)
497        {
498        case PR_DIRECTIVE_ELSE:
499        case PR_DIRECTIVE_ELIF:
500
501            if (Gbl_DirectiveStack &&
502                Gbl_DirectiveStack->IgnoringThisCodeBlock)
503            {
504                PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
505                return;
506            }
507            break;
508
509        default:
510            break;
511        }
512    }
513
514    /*
515     * Need to always check for #else, #elif, #endif regardless of
516     * whether we are ignoring the current code block, since these
517     * are conditional code block terminators.
518     */
519    switch (Directive)
520    {
521    case PR_DIRECTIVE_ELSE:
522
523        Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
524        PrDbgPrint ("Executing", "else block");
525        return;
526
527    case PR_DIRECTIVE_ELIF:
528
529        Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
530        Directive = PR_DIRECTIVE_IF;
531
532        if (Gbl_IgnoringThisCodeBlock == TRUE)
533        {
534            /* Not executing the ELSE part -- all done here */
535            PrDbgPrint ("Ignoring", "elif block");
536            return;
537        }
538
539        /*
540         * After this, we will execute the IF part further below.
541         * First, however, pop off the original #if directive.
542         */
543        if (ACPI_FAILURE (PrPopDirective ()))
544        {
545            PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
546                THIS_TOKEN_OFFSET (DirectiveToken));
547        }
548
549        PrDbgPrint ("Executing", "elif block");
550        break;
551
552    case PR_DIRECTIVE_ENDIF:
553
554        PrDbgPrint ("Executing", "endif");
555
556        /* Pop the owning #if/#ifdef/#ifndef */
557
558        if (ACPI_FAILURE (PrPopDirective ()))
559        {
560            PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
561                THIS_TOKEN_OFFSET (DirectiveToken));
562        }
563        return;
564
565    default:
566        break;
567    }
568
569    /* Most directives have at least one argument */
570
571    if (Gbl_DirectiveInfo[Directive].ArgCount >= 1)
572    {
573        Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
574        if (!Token)
575        {
576            goto SyntaxError;
577        }
578    }
579
580    if (Gbl_DirectiveInfo[Directive].ArgCount >= 2)
581    {
582        Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
583        if (!Token2)
584        {
585            goto SyntaxError;
586        }
587    }
588
589    /*
590     * At this point, if we are ignoring the current code block,
591     * do not process any more directives (i.e., ignore them also.)
592     * For "if" style directives, open/push a new block anyway. We
593     * must do this to keep track of #endif directives
594     */
595    if (Gbl_IgnoringThisCodeBlock)
596    {
597        switch (Directive)
598        {
599        case PR_DIRECTIVE_IF:
600        case PR_DIRECTIVE_IFDEF:
601        case PR_DIRECTIVE_IFNDEF:
602
603            PrPushDirective (Directive, Token);
604            PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
605            break;
606
607        default:
608            break;
609        }
610
611        return;
612    }
613
614    /*
615     * Execute the directive
616     */
617    PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
618
619    switch (Directive)
620    {
621    case PR_DIRECTIVE_IF:
622
623        TokenOffset = Token - Gbl_MainTokenBuffer;
624
625        /* Need to expand #define macros in the expression string first */
626
627        Status = PrResolveIntegerExpression (
628            &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
629        if (ACPI_FAILURE (Status))
630        {
631            return;
632        }
633
634        PrPushDirective (Directive, Token);
635        if (!Value)
636        {
637            Gbl_IgnoringThisCodeBlock = TRUE;
638        }
639
640        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
641            "Resolved #if: %8.8X%8.8X %s\n",
642            Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
643            Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
644        break;
645
646    case PR_DIRECTIVE_IFDEF:
647
648        PrPushDirective (Directive, Token);
649        if (!PrMatchDefine (Token))
650        {
651            Gbl_IgnoringThisCodeBlock = TRUE;
652        }
653
654        PrDbgPrint ("Evaluated", "ifdef");
655        break;
656
657    case PR_DIRECTIVE_IFNDEF:
658
659        PrPushDirective (Directive, Token);
660        if (PrMatchDefine (Token))
661        {
662            Gbl_IgnoringThisCodeBlock = TRUE;
663        }
664
665        PrDbgPrint ("Evaluated", "ifndef");
666        break;
667
668    case PR_DIRECTIVE_DEFINE:
669        /*
670         * By definition, if first char after the name is a paren,
671         * this is a function macro.
672         */
673        TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
674        if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
675        {
676#ifndef MACROS_SUPPORTED
677            AcpiOsPrintf (
678                "%s ERROR - line %u: #define macros are not supported yet\n",
679                Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber);
680            exit(1);
681#else
682            PrAddMacro (Token, Next);
683#endif
684        }
685        else
686        {
687            /* Use the remainder of the line for the #define */
688
689            Token2 = *Next;
690            if (Token2)
691            {
692                while ((*Token2 == ' ') || (*Token2 == '\t'))
693                {
694                    Token2++;
695                }
696
697                End = Token2;
698                while (*End != '\n')
699                {
700                    End++;
701                }
702
703                *End = 0;
704            }
705            else
706            {
707                Token2 = "";
708            }
709#if 0
710            Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
711            if (!Token2)
712            {
713                Token2 = "";
714            }
715#endif
716            DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
717                "New #define: %s->%s\n",
718                Gbl_LogicalLineNumber, Token, Token2);
719
720            PrAddDefine (Token, Token2, FALSE);
721        }
722        break;
723
724    case PR_DIRECTIVE_ERROR:
725
726        /* Note: No macro expansion */
727
728        PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
729            THIS_TOKEN_OFFSET (Token));
730
731        Gbl_SourceLine = 0;
732        Gbl_NextError = Gbl_ErrorLog;
733        CmCleanupAndExit ();
734        exit(1);
735
736    case PR_DIRECTIVE_INCLUDE:
737
738        Token = PrGetNextToken (NULL, " \"<>", Next);
739        if (!Token)
740        {
741            goto SyntaxError;
742        }
743
744        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
745            "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
746            Token, Gbl_CurrentLineNumber);
747
748        PrDoIncludeFile (Token);
749        break;
750
751    case PR_DIRECTIVE_INCLUDEBUFFER:
752
753        Token = PrGetNextToken (NULL, " \"<>", Next);
754        if (!Token)
755        {
756            goto SyntaxError;
757        }
758
759        Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
760        if (!Token2)
761        {
762            goto SyntaxError;
763        }
764
765        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
766            "Start #includebuffer input from file \"%s\", buffer name %s\n",
767            Gbl_CurrentLineNumber, Token, Token2);
768
769        PrDoIncludeBuffer (Token, Token2);
770        break;
771
772    case PR_DIRECTIVE_LINE:
773
774        TokenOffset = Token - Gbl_MainTokenBuffer;
775
776        Status = PrResolveIntegerExpression (
777            &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
778        if (ACPI_FAILURE (Status))
779        {
780            return;
781        }
782
783        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
784            "User #line invocation %s\n", Gbl_CurrentLineNumber,
785            Token);
786
787        Gbl_CurrentLineNumber = (UINT32) Value;
788
789        /* Emit #line into the preprocessor file */
790
791        FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
792            Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
793        break;
794
795    case PR_DIRECTIVE_PRAGMA:
796
797        if (!strcmp (Token, "disable"))
798        {
799            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
800            if (!Token)
801            {
802                goto SyntaxError;
803            }
804
805            TokenOffset = Token - Gbl_MainTokenBuffer;
806            AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
807        }
808        else if (!strcmp (Token, "message"))
809        {
810            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
811            if (!Token)
812            {
813                goto SyntaxError;
814            }
815
816            TokenOffset = Token - Gbl_MainTokenBuffer;
817            AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
818        }
819        else
820        {
821            PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
822                THIS_TOKEN_OFFSET (Token));
823            return;
824        }
825
826        break;
827
828    case PR_DIRECTIVE_UNDEF:
829
830        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
831            "#undef: %s\n", Gbl_CurrentLineNumber, Token);
832
833        PrRemoveDefine (Token);
834        break;
835
836    case PR_DIRECTIVE_WARNING:
837
838        PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
839            THIS_TOKEN_OFFSET (Token));
840
841        Gbl_SourceLine = 0;
842        Gbl_NextError = Gbl_ErrorLog;
843        break;
844
845    default:
846
847        /* Should never get here */
848        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
849            "Unrecognized directive: %u\n",
850            Gbl_CurrentLineNumber, Directive);
851        break;
852    }
853
854    return;
855
856SyntaxError:
857
858    PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
859        THIS_TOKEN_OFFSET (DirectiveToken));
860    return;
861}
862
863
864/*******************************************************************************
865 *
866 * FUNCTION:    PrGetNextLine, PrGetNextLineInit
867 *
868 * PARAMETERS:  Handle              - Open file handle for the source file
869 *
870 * RETURN:      Status of the GetLine operation:
871 *              AE_OK               - Normal line, OK status
872 *              ASL_IGNORE_LINE     - Line is blank or part of a multi-line
873 *                                      comment
874 *              ASL_EOF             - End-of-file reached
875 *
876 * DESCRIPTION: Get the next text line from the input file. Does not strip
877 *              comments.
878 *
879 ******************************************************************************/
880
881#define PR_NORMAL_TEXT          0
882#define PR_MULTI_LINE_COMMENT   1
883#define PR_SINGLE_LINE_COMMENT  2
884#define PR_QUOTED_STRING        3
885
886static UINT8                    AcpiGbl_LineScanState = PR_NORMAL_TEXT;
887
888static void
889PrGetNextLineInit (
890    void)
891{
892    AcpiGbl_LineScanState = 0;
893}
894
895static UINT32
896PrGetNextLine (
897    FILE                    *Handle)
898{
899    UINT32                  i;
900    int                     c = 0;
901    int                     PreviousChar;
902
903
904    /* Always clear the global line buffer */
905
906    memset (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize);
907    for (i = 0; ;)
908    {
909        /*
910         * If line is too long, expand the line buffers. Also increases
911         * Gbl_LineBufferSize.
912         */
913        if (i >= Gbl_LineBufferSize)
914        {
915            UtExpandLineBuffers ();
916        }
917
918        PreviousChar = c;
919        c = getc (Handle);
920        if (c == EOF)
921        {
922            /*
923             * On EOF: If there is anything in the line buffer, terminate
924             * it with a newline, and catch the EOF on the next call
925             * to this function.
926             */
927            if (i > 0)
928            {
929                Gbl_CurrentLineBuffer[i] = '\n';
930                return (AE_OK);
931            }
932
933            return (ASL_EOF);
934        }
935
936        /* Update state machine as necessary */
937
938        switch (AcpiGbl_LineScanState)
939        {
940        case PR_NORMAL_TEXT:
941
942            /* Check for multi-line comment start */
943
944            if ((PreviousChar == '/') && (c == '*'))
945            {
946                AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT;
947            }
948
949            /* Check for single-line comment start */
950
951            else if ((PreviousChar == '/') && (c == '/'))
952            {
953                AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT;
954            }
955
956            /* Check for quoted string start */
957
958            else if (PreviousChar == '"')
959            {
960                AcpiGbl_LineScanState = PR_QUOTED_STRING;
961            }
962            break;
963
964        case PR_QUOTED_STRING:
965
966            if (PreviousChar == '"')
967            {
968                AcpiGbl_LineScanState = PR_NORMAL_TEXT;
969            }
970            break;
971
972        case PR_MULTI_LINE_COMMENT:
973
974            /* Check for multi-line comment end */
975
976            if ((PreviousChar == '*') && (c == '/'))
977            {
978                AcpiGbl_LineScanState = PR_NORMAL_TEXT;
979            }
980            break;
981
982        case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */
983        default:
984            break;
985        }
986
987        /* Always copy the character into line buffer */
988
989        Gbl_CurrentLineBuffer[i] = (char) c;
990        i++;
991
992        /* Always exit on end-of-line */
993
994        if (c == '\n')
995        {
996            /* Handle multi-line comments */
997
998            if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT)
999            {
1000                return (ASL_IGNORE_LINE);
1001            }
1002
1003            /* End of single-line comment */
1004
1005            if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT)
1006            {
1007                AcpiGbl_LineScanState = PR_NORMAL_TEXT;
1008                return (AE_OK);
1009            }
1010
1011            /* Blank line */
1012
1013            if (i == 1)
1014            {
1015                return (ASL_IGNORE_LINE);
1016            }
1017
1018            return (AE_OK);
1019        }
1020    }
1021}
1022
1023
1024/*******************************************************************************
1025 *
1026 * FUNCTION:    PrMatchDirective
1027 *
1028 * PARAMETERS:  Directive           - Pointer to directive name token
1029 *
1030 * RETURN:      Index into command array, -1 if not found
1031 *
1032 * DESCRIPTION: Lookup the incoming directive in the known directives table.
1033 *
1034 ******************************************************************************/
1035
1036static int
1037PrMatchDirective (
1038    char                    *Directive)
1039{
1040    int                     i;
1041
1042
1043    if (!Directive || Directive[0] == 0)
1044    {
1045        return (ASL_DIRECTIVE_NOT_FOUND);
1046    }
1047
1048    for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
1049    {
1050        if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
1051        {
1052            return (i);
1053        }
1054    }
1055
1056    return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
1057}
1058
1059
1060/*******************************************************************************
1061 *
1062 * FUNCTION:    PrPushDirective
1063 *
1064 * PARAMETERS:  Directive           - Encoded directive ID
1065 *              Argument            - String containing argument to the
1066 *                                    directive
1067 *
1068 * RETURN:      None
1069 *
1070 * DESCRIPTION: Push an item onto the directive stack. Used for processing
1071 *              nested #if/#else type conditional compilation directives.
1072 *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
1073 *              a block.
1074 *
1075 ******************************************************************************/
1076
1077static void
1078PrPushDirective (
1079    int                     Directive,
1080    char                    *Argument)
1081{
1082    DIRECTIVE_INFO          *Info;
1083
1084
1085    /* Allocate and populate a stack info item */
1086
1087    Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
1088
1089    Info->Next = Gbl_DirectiveStack;
1090    Info->Directive = Directive;
1091    Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
1092    strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
1093
1094    DbgPrint (ASL_DEBUG_OUTPUT,
1095        "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
1096        Gbl_CurrentLineNumber, Gbl_IfDepth,
1097        Gbl_IgnoringThisCodeBlock ? "I" : "E",
1098        Gbl_IfDepth * 4, " ",
1099        Gbl_DirectiveInfo[Directive].Name,
1100        Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1101
1102    /* Push new item */
1103
1104    Gbl_DirectiveStack = Info;
1105    Gbl_IfDepth++;
1106}
1107
1108
1109/*******************************************************************************
1110 *
1111 * FUNCTION:    PrPopDirective
1112 *
1113 * PARAMETERS:  None
1114 *
1115 * RETURN:      Status. Error if the stack is empty.
1116 *
1117 * DESCRIPTION: Pop an item off the directive stack. Used for processing
1118 *              nested #if/#else type conditional compilation directives.
1119 *              Specifically: Used on detection of #elif and #endif to remove
1120 *              the original #if/#ifdef/#ifndef from the stack and close
1121 *              the block.
1122 *
1123 ******************************************************************************/
1124
1125static ACPI_STATUS
1126PrPopDirective (
1127    void)
1128{
1129    DIRECTIVE_INFO          *Info;
1130
1131
1132    /* Check for empty stack */
1133
1134    Info = Gbl_DirectiveStack;
1135    if (!Info)
1136    {
1137        return (AE_ERROR);
1138    }
1139
1140    /* Pop one item, keep globals up-to-date */
1141
1142    Gbl_IfDepth--;
1143    Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
1144    Gbl_DirectiveStack = Info->Next;
1145
1146    DbgPrint (ASL_DEBUG_OUTPUT,
1147        "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
1148        Gbl_CurrentLineNumber, Gbl_IfDepth,
1149        Gbl_IgnoringThisCodeBlock ? "I" : "E",
1150        Gbl_IfDepth * 4, " ",
1151        Gbl_DirectiveInfo[Info->Directive].Name,
1152        Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1153
1154    ACPI_FREE (Info);
1155    return (AE_OK);
1156}
1157
1158
1159/*******************************************************************************
1160 *
1161 * FUNCTION:    PrDbgPrint
1162 *
1163 * PARAMETERS:  Action              - Action being performed
1164 *              DirectiveName       - Directive being processed
1165 *
1166 * RETURN:      None
1167 *
1168 * DESCRIPTION: Special debug print for directive processing.
1169 *
1170 ******************************************************************************/
1171
1172static void
1173PrDbgPrint (
1174    char                    *Action,
1175    char                    *DirectiveName)
1176{
1177
1178    DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
1179        "%*s %s #%s, IfDepth %u\n",
1180        Gbl_CurrentLineNumber, Gbl_IfDepth,
1181        Gbl_IgnoringThisCodeBlock ? "I" : "E",
1182        Gbl_IfDepth * 4, " ",
1183        Action, DirectiveName, Gbl_IfDepth);
1184}
1185
1186
1187/*******************************************************************************
1188 *
1189 * FUNCTION:    PrDoIncludeFile
1190 *
1191 * PARAMETERS:  Pathname                - Name of the input file
1192 *
1193 * RETURN:      None.
1194 *
1195 * DESCRIPTION: Open an include file, from #include.
1196 *
1197 ******************************************************************************/
1198
1199static void
1200PrDoIncludeFile (
1201    char                    *Pathname)
1202{
1203    char                    *FullPathname;
1204
1205
1206    (void) PrOpenIncludeFile (Pathname, "r", &FullPathname);
1207}
1208
1209
1210/*******************************************************************************
1211 *
1212 * FUNCTION:    PrDoIncludeBuffer
1213 *
1214 * PARAMETERS:  Pathname                - Name of the input binary file
1215 *              BufferName              - ACPI namepath of the buffer
1216 *
1217 * RETURN:      None.
1218 *
1219 * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents
1220 *              of the file are emitted into the buffer object as ascii
1221 *              hex data. From #includebuffer.
1222 *
1223 ******************************************************************************/
1224
1225static void
1226PrDoIncludeBuffer (
1227    char                    *Pathname,
1228    char                    *BufferName)
1229{
1230    char                    *FullPathname;
1231    FILE                    *BinaryBufferFile;
1232    UINT32                  i = 0;
1233    UINT8                   c;
1234
1235
1236    BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname);
1237    if (!BinaryBufferFile)
1238    {
1239        return;
1240    }
1241
1242    /* Emit "Name (XXXX, Buffer() {" header */
1243
1244    FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName);
1245
1246    /* Dump the entire file in ascii hex format */
1247
1248    while (fread (&c, 1, 1, BinaryBufferFile))
1249    {
1250        if (!(i % 8))
1251        {
1252            FlPrintFile (ASL_FILE_PREPROCESSOR, "\n   ", c);
1253        }
1254
1255        FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c);
1256        i++;
1257    }
1258
1259    DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
1260        "#includebuffer: read %u bytes from %s\n",
1261        Gbl_CurrentLineNumber, i, FullPathname);
1262
1263    /* Close the Name() operator */
1264
1265    FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName);
1266    fclose (BinaryBufferFile);
1267}
1268