1233237Sjkim/******************************************************************************
2233237Sjkim *
3233237Sjkim * Module Name: prscan - Preprocessor start-up and file scan module
4233237Sjkim *
5233237Sjkim *****************************************************************************/
6233237Sjkim
7233237Sjkim/*
8245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp.
9233237Sjkim * All rights reserved.
10233237Sjkim *
11233237Sjkim * Redistribution and use in source and binary forms, with or without
12233237Sjkim * modification, are permitted provided that the following conditions
13233237Sjkim * are met:
14233237Sjkim * 1. Redistributions of source code must retain the above copyright
15233237Sjkim *    notice, this list of conditions, and the following disclaimer,
16233237Sjkim *    without modification.
17233237Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18233237Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19233237Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20233237Sjkim *    including a substantially similar Disclaimer requirement for further
21233237Sjkim *    binary redistribution.
22233237Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23233237Sjkim *    of any contributors may be used to endorse or promote products derived
24233237Sjkim *    from this software without specific prior written permission.
25233237Sjkim *
26233237Sjkim * Alternatively, this software may be distributed under the terms of the
27233237Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28233237Sjkim * Software Foundation.
29233237Sjkim *
30233237Sjkim * NO WARRANTY
31233237Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32233237Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33233237Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34233237Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35233237Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36233237Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37233237Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38233237Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39233237Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40233237Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41233237Sjkim * POSSIBILITY OF SUCH DAMAGES.
42233237Sjkim */
43233237Sjkim
44233237Sjkim#define _DECLARE_PR_GLOBALS
45233237Sjkim
46233250Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
47233250Sjkim#include <contrib/dev/acpica/compiler/dtcompiler.h>
48233237Sjkim
49233237Sjkim/*
50233237Sjkim * TBDs:
51233237Sjkim *
52233237Sjkim * No nested macros, maybe never
53233237Sjkim * Implement ASL "Include" as well as "#include" here?
54233237Sjkim */
55233237Sjkim#define _COMPONENT          ASL_PREPROCESSOR
56233237Sjkim        ACPI_MODULE_NAME    ("prscan")
57233237Sjkim
58233237Sjkim
59233237Sjkim/* Local prototypes */
60233237Sjkim
61233237Sjkimstatic void
62233237SjkimPrPreprocessInputFile (
63233237Sjkim    void);
64233237Sjkim
65233237Sjkimstatic void
66233237SjkimPrDoDirective (
67233237Sjkim    char                    *DirectiveToken,
68252279Sjkim    char                    **Next);
69233237Sjkim
70233237Sjkimstatic int
71233237SjkimPrMatchDirective (
72233237Sjkim    char                    *Directive);
73233237Sjkim
74252279Sjkimstatic void
75252279SjkimPrPushDirective (
76252279Sjkim    int                     Directive,
77252279Sjkim    char                    *Argument);
78252279Sjkim
79252279Sjkimstatic ACPI_STATUS
80252279SjkimPrPopDirective (
81252279Sjkim    void);
82252279Sjkim
83252279Sjkimstatic void
84252279SjkimPrDbgPrint (
85252279Sjkim    char                    *Action,
86252279Sjkim    char                    *DirectiveName);
87252279Sjkim
88252279Sjkim
89233237Sjkim/*
90233237Sjkim * Supported preprocessor directives
91233237Sjkim */
92233237Sjkimstatic const PR_DIRECTIVE_INFO      Gbl_DirectiveInfo[] =
93233237Sjkim{
94233237Sjkim    {"define",  1},
95233237Sjkim    {"elif",    0}, /* Converted to #else..#if internally */
96233237Sjkim    {"else",    0},
97233237Sjkim    {"endif",   0},
98233237Sjkim    {"error",   1},
99233237Sjkim    {"if",      1},
100233237Sjkim    {"ifdef",   1},
101233237Sjkim    {"ifndef",  1},
102233237Sjkim    {"include", 0}, /* Argument is not standard format, so 0 */
103233237Sjkim    {"line",    1},
104233237Sjkim    {"pragma",  1},
105233237Sjkim    {"undef",   1},
106233237Sjkim    {"warning", 1},
107233237Sjkim    {NULL,      0}
108233237Sjkim};
109233237Sjkim
110233237Sjkimenum Gbl_DirectiveIndexes
111233237Sjkim{
112233237Sjkim    PR_DIRECTIVE_DEFINE = 0,
113233237Sjkim    PR_DIRECTIVE_ELIF,
114233237Sjkim    PR_DIRECTIVE_ELSE,
115233237Sjkim    PR_DIRECTIVE_ENDIF,
116233237Sjkim    PR_DIRECTIVE_ERROR,
117233237Sjkim    PR_DIRECTIVE_IF,
118233237Sjkim    PR_DIRECTIVE_IFDEF,
119233237Sjkim    PR_DIRECTIVE_IFNDEF,
120233237Sjkim    PR_DIRECTIVE_INCLUDE,
121233237Sjkim    PR_DIRECTIVE_LINE,
122233237Sjkim    PR_DIRECTIVE_PRAGMA,
123233237Sjkim    PR_DIRECTIVE_UNDEF,
124233237Sjkim    PR_DIRECTIVE_WARNING,
125233237Sjkim};
126233237Sjkim
127233237Sjkim#define ASL_DIRECTIVE_NOT_FOUND     -1
128233237Sjkim
129233237Sjkim
130233237Sjkim/*******************************************************************************
131233237Sjkim *
132233237Sjkim * FUNCTION:    PrInitializePreprocessor
133233237Sjkim *
134233237Sjkim * PARAMETERS:  None
135233237Sjkim *
136233237Sjkim * RETURN:      None
137233237Sjkim *
138233237Sjkim * DESCRIPTION: Startup initialization for the Preprocessor.
139233237Sjkim *
140233237Sjkim ******************************************************************************/
141233237Sjkim
142233237Sjkimvoid
143233237SjkimPrInitializePreprocessor (
144233237Sjkim    void)
145233237Sjkim{
146233237Sjkim    /* Init globals and the list of #defines */
147233237Sjkim
148233237Sjkim    PrInitializeGlobals ();
149233237Sjkim    Gbl_DefineList = NULL;
150233237Sjkim}
151233237Sjkim
152233237Sjkim
153233237Sjkim/*******************************************************************************
154233237Sjkim *
155233237Sjkim * FUNCTION:    PrInitializeGlobals
156233237Sjkim *
157233237Sjkim * PARAMETERS:  None
158233237Sjkim *
159233237Sjkim * RETURN:      None
160233237Sjkim *
161233237Sjkim * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup
162233237Sjkim *              initialization and re-initialization between compiles during
163233237Sjkim *              a multiple source file compile.
164233237Sjkim *
165233237Sjkim ******************************************************************************/
166233237Sjkim
167233237Sjkimvoid
168233237SjkimPrInitializeGlobals (
169233237Sjkim    void)
170233237Sjkim{
171233237Sjkim    /* Init globals */
172233237Sjkim
173233237Sjkim    Gbl_InputFileList = NULL;
174233237Sjkim    Gbl_CurrentLineNumber = 0;
175233237Sjkim    Gbl_PreprocessorLineNumber = 1;
176233237Sjkim    Gbl_PreprocessorError = FALSE;
177252279Sjkim
178252279Sjkim    /* These are used to track #if/#else blocks (possibly nested) */
179252279Sjkim
180252279Sjkim    Gbl_IfDepth = 0;
181252279Sjkim    Gbl_IgnoringThisCodeBlock = FALSE;
182252279Sjkim    Gbl_DirectiveStack = NULL;
183233237Sjkim}
184233237Sjkim
185233237Sjkim
186233237Sjkim/*******************************************************************************
187233237Sjkim *
188233237Sjkim * FUNCTION:    PrTerminatePreprocessor
189233237Sjkim *
190233237Sjkim * PARAMETERS:  None
191233237Sjkim *
192233237Sjkim * RETURN:      None
193233237Sjkim *
194233237Sjkim * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any
195233237Sjkim *              defines that were specified on the command line, in order to
196233237Sjkim *              support multiple compiles with a single compiler invocation.
197233237Sjkim *
198233237Sjkim ******************************************************************************/
199233237Sjkim
200233237Sjkimvoid
201233237SjkimPrTerminatePreprocessor (
202233237Sjkim    void)
203233237Sjkim{
204233237Sjkim    PR_DEFINE_INFO          *DefineInfo;
205233237Sjkim
206233237Sjkim
207233237Sjkim    /*
208233237Sjkim     * The persistent defines (created on the command line) are always at the
209233237Sjkim     * end of the list. We save them.
210233237Sjkim     */
211233237Sjkim    while ((Gbl_DefineList) && (!Gbl_DefineList->Persist))
212233237Sjkim    {
213233237Sjkim        DefineInfo = Gbl_DefineList;
214233237Sjkim        Gbl_DefineList = DefineInfo->Next;
215233237Sjkim
216233237Sjkim        ACPI_FREE (DefineInfo->Replacement);
217233237Sjkim        ACPI_FREE (DefineInfo->Identifier);
218233237Sjkim        ACPI_FREE (DefineInfo);
219233237Sjkim    }
220233237Sjkim}
221233237Sjkim
222233237Sjkim
223233237Sjkim/*******************************************************************************
224233237Sjkim *
225233237Sjkim * FUNCTION:    PrDoPreprocess
226233237Sjkim *
227233237Sjkim * PARAMETERS:  None
228233237Sjkim *
229252279Sjkim * RETURN:      None
230233237Sjkim *
231233237Sjkim * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must
232233237Sjkim *              be already open. Handles multiple input files via the
233233237Sjkim *              #include directive.
234233237Sjkim *
235233237Sjkim ******************************************************************************/
236233237Sjkim
237252279Sjkimvoid
238233237SjkimPrDoPreprocess (
239233237Sjkim    void)
240233237Sjkim{
241233237Sjkim    BOOLEAN                 MoreInputFiles;
242233237Sjkim
243233237Sjkim
244233237Sjkim    DbgPrint (ASL_DEBUG_OUTPUT, "Starting preprocessing phase\n\n");
245233237Sjkim
246233237Sjkim
247233237Sjkim    FlSeekFile (ASL_FILE_INPUT, 0);
248233237Sjkim    PrDumpPredefinedNames ();
249233237Sjkim
250233237Sjkim    /* Main preprocessor loop, handles include files */
251233237Sjkim
252233237Sjkim    do
253233237Sjkim    {
254233237Sjkim        PrPreprocessInputFile ();
255233237Sjkim        MoreInputFiles = PrPopInputFileStack ();
256233237Sjkim
257233237Sjkim    } while (MoreInputFiles);
258233237Sjkim
259252279Sjkim    /* Point compiler input to the new preprocessor output file (.i) */
260233237Sjkim
261233237Sjkim    FlCloseFile (ASL_FILE_INPUT);
262233237Sjkim    Gbl_Files[ASL_FILE_INPUT].Handle = Gbl_Files[ASL_FILE_PREPROCESSOR].Handle;
263233237Sjkim    AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle;
264233237Sjkim
265233237Sjkim    /* Reset globals to allow compiler to run */
266233237Sjkim
267233237Sjkim    FlSeekFile (ASL_FILE_INPUT, 0);
268233237Sjkim    Gbl_CurrentLineNumber = 1;
269233237Sjkim
270233237Sjkim    DbgPrint (ASL_DEBUG_OUTPUT, "Preprocessing phase complete \n\n");
271233237Sjkim}
272233237Sjkim
273233237Sjkim
274233237Sjkim/*******************************************************************************
275233237Sjkim *
276233237Sjkim * FUNCTION:    PrPreprocessInputFile
277233237Sjkim *
278233237Sjkim * PARAMETERS:  None
279233237Sjkim *
280233237Sjkim * RETURN:      None
281233237Sjkim *
282233237Sjkim * DESCRIPTION: Preprocess one entire file, line-by-line.
283233237Sjkim *
284233237Sjkim * Input:  Raw user ASL from ASL_FILE_INPUT
285233237Sjkim * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR
286233237Sjkim *
287233237Sjkim ******************************************************************************/
288233237Sjkim
289233237Sjkimstatic void
290233237SjkimPrPreprocessInputFile (
291233237Sjkim    void)
292233237Sjkim{
293233237Sjkim    UINT32                  Offset;
294233237Sjkim    char                    *Token;
295233237Sjkim    char                    *ReplaceString;
296233237Sjkim    PR_DEFINE_INFO          *DefineInfo;
297233237Sjkim    ACPI_SIZE               TokenOffset;
298233237Sjkim    char                    *Next;
299233237Sjkim    int                     OffsetAdjust;
300233237Sjkim
301233237Sjkim
302233237Sjkim    /* Scan line-by-line. Comments and blank lines are skipped by this function */
303233237Sjkim
304233237Sjkim    while ((Offset = DtGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF)
305233237Sjkim    {
306233237Sjkim        /* Need a copy of the input line for strok() */
307233237Sjkim
308233237Sjkim        strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
309233237Sjkim        Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
310233237Sjkim        OffsetAdjust = 0;
311233237Sjkim
312233237Sjkim        /* All preprocessor directives must begin with '#' */
313233237Sjkim
314233237Sjkim        if (Token && (*Token == '#'))
315233237Sjkim        {
316233237Sjkim            if (strlen (Token) == 1)
317233237Sjkim            {
318233237Sjkim                Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
319233237Sjkim            }
320233237Sjkim            else
321233237Sjkim            {
322233237Sjkim                Token++;    /* Skip leading # */
323233237Sjkim            }
324233237Sjkim
325233237Sjkim            /* Execute the directive, do not write line to output file */
326233237Sjkim
327252279Sjkim            PrDoDirective (Token, &Next);
328233237Sjkim            continue;
329233237Sjkim        }
330233237Sjkim
331233237Sjkim        /*
332233237Sjkim         * If we are currently within the part of an IF/ELSE block that is
333233237Sjkim         * FALSE, ignore the line and do not write it to the output file.
334233237Sjkim         * This continues until an #else or #endif is encountered.
335233237Sjkim         */
336252279Sjkim        if (Gbl_IgnoringThisCodeBlock)
337233237Sjkim        {
338233237Sjkim            continue;
339233237Sjkim        }
340233237Sjkim
341233237Sjkim        /* Match and replace all #defined names within this source line */
342233237Sjkim
343233237Sjkim        while (Token)
344233237Sjkim        {
345233237Sjkim            DefineInfo = PrMatchDefine (Token);
346233237Sjkim            if (DefineInfo)
347233237Sjkim            {
348233237Sjkim                if (DefineInfo->Body)
349233237Sjkim                {
350233237Sjkim                    /* This is a macro */
351233237Sjkim
352233237Sjkim                    DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
353233237Sjkim                        "Matched Macro: %s->%s\n",
354233237Sjkim                        Gbl_CurrentLineNumber, DefineInfo->Identifier,
355233237Sjkim                        DefineInfo->Replacement);
356233237Sjkim
357233237Sjkim                    PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
358233237Sjkim                        DefineInfo, &Next);
359233237Sjkim                }
360233237Sjkim                else
361233237Sjkim                {
362233237Sjkim                    ReplaceString = DefineInfo->Replacement;
363233237Sjkim
364233237Sjkim                    /* Replace the name in the original line buffer */
365233237Sjkim
366233237Sjkim                    TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
367233237Sjkim                    PrReplaceData (
368233237Sjkim                        &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
369233237Sjkim                        ReplaceString, strlen (ReplaceString));
370233237Sjkim
371233237Sjkim                    /* Adjust for length difference between old and new name length */
372233237Sjkim
373233237Sjkim                    OffsetAdjust += strlen (ReplaceString) - strlen (Token);
374233237Sjkim
375233237Sjkim                    DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
376233237Sjkim                        "Matched #define: %s->%s\n",
377233237Sjkim                        Gbl_CurrentLineNumber, Token,
378233237Sjkim                        *ReplaceString ? ReplaceString : "(NULL STRING)");
379233237Sjkim                }
380233237Sjkim            }
381233237Sjkim
382233237Sjkim            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
383233237Sjkim        }
384233237Sjkim
385233237Sjkim#if 0
386233237Sjkim/* Line prefix */
387233237Sjkim        FlPrintFile (ASL_FILE_PREPROCESSOR, "/* %14s  %.5u  i:%.5u */ ",
388233237Sjkim            Gbl_Files[ASL_FILE_INPUT].Filename,
389233237Sjkim            Gbl_CurrentLineNumber, Gbl_PreprocessorLineNumber);
390233237Sjkim#endif
391233237Sjkim
392234623Sjkim        /*
393234623Sjkim         * Emit a #line directive if necessary, to keep the line numbers in
394234623Sjkim         * the (.i) file synchronized with the original source code file, so
395234623Sjkim         * that the correct line number appears in any error messages
396234623Sjkim         * generated by the actual compiler.
397234623Sjkim         */
398234623Sjkim        if (Gbl_CurrentLineNumber > (Gbl_PreviousLineNumber + 1))
399234623Sjkim        {
400234623Sjkim            FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u\n",
401234623Sjkim                Gbl_CurrentLineNumber);
402234623Sjkim        }
403234623Sjkim
404234623Sjkim        Gbl_PreviousLineNumber = Gbl_CurrentLineNumber;
405234623Sjkim        Gbl_PreprocessorLineNumber++;
406234623Sjkim
407234623Sjkim        /*
408234623Sjkim         * Now we can write the possibly modified source line to the
409234623Sjkim         * preprocessor (.i) file
410234623Sjkim         */
411233237Sjkim        FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
412233237Sjkim            strlen (Gbl_CurrentLineBuffer));
413233237Sjkim    }
414233237Sjkim}
415233237Sjkim
416233237Sjkim
417233237Sjkim/*******************************************************************************
418233237Sjkim *
419233237Sjkim * FUNCTION:    PrDoDirective
420233237Sjkim *
421233237Sjkim * PARAMETERS:  Directive               - Pointer to directive name token
422233237Sjkim *              Next                    - "Next" buffer from GetNextToken
423233237Sjkim *
424252279Sjkim * RETURN:      None.
425233237Sjkim *
426233237Sjkim * DESCRIPTION: Main processing for all preprocessor directives
427233237Sjkim *
428233237Sjkim ******************************************************************************/
429233237Sjkim
430233237Sjkimstatic void
431233237SjkimPrDoDirective (
432233237Sjkim    char                    *DirectiveToken,
433252279Sjkim    char                    **Next)
434233237Sjkim{
435233237Sjkim    char                    *Token = Gbl_MainTokenBuffer;
436233237Sjkim    char                    *Token2;
437233237Sjkim    char                    *End;
438233237Sjkim    UINT64                  Value;
439233237Sjkim    ACPI_SIZE               TokenOffset;
440233237Sjkim    int                     Directive;
441233237Sjkim    ACPI_STATUS             Status;
442233237Sjkim
443233237Sjkim
444233237Sjkim    if (!DirectiveToken)
445233237Sjkim    {
446233237Sjkim        goto SyntaxError;
447233237Sjkim    }
448233237Sjkim
449233237Sjkim    Directive = PrMatchDirective (DirectiveToken);
450233237Sjkim    if (Directive == ASL_DIRECTIVE_NOT_FOUND)
451233237Sjkim    {
452233237Sjkim        PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
453233237Sjkim            THIS_TOKEN_OFFSET (DirectiveToken));
454233237Sjkim
455233237Sjkim        DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
456233237Sjkim            "#%s: Unknown directive\n",
457233237Sjkim            Gbl_CurrentLineNumber, DirectiveToken);
458233237Sjkim        return;
459233237Sjkim    }
460233237Sjkim
461252279Sjkim    /*
462252279Sjkim     * If we are currently ignoring this block and we encounter a #else or
463252279Sjkim     * #elif, we must ignore their blocks also if the parent block is also
464252279Sjkim     * being ignored.
465252279Sjkim     */
466252279Sjkim    if (Gbl_IgnoringThisCodeBlock)
467252279Sjkim    {
468252279Sjkim        switch (Directive)
469252279Sjkim        {
470252279Sjkim        case PR_DIRECTIVE_ELSE:
471252279Sjkim        case PR_DIRECTIVE_ELIF:
472233237Sjkim
473252279Sjkim            if (Gbl_DirectiveStack && Gbl_DirectiveStack->IgnoringThisCodeBlock)
474252279Sjkim            {
475252279Sjkim                PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
476252279Sjkim                return;
477252279Sjkim            }
478252279Sjkim            break;
479252279Sjkim
480252279Sjkim        default:
481252279Sjkim            break;
482252279Sjkim        }
483233237Sjkim    }
484233237Sjkim
485233237Sjkim    /*
486233237Sjkim     * Need to always check for #else, #elif, #endif regardless of
487233237Sjkim     * whether we are ignoring the current code block, since these
488233237Sjkim     * are conditional code block terminators.
489233237Sjkim     */
490233237Sjkim    switch (Directive)
491233237Sjkim    {
492252279Sjkim    case PR_DIRECTIVE_ELSE:
493252279Sjkim
494252279Sjkim        Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
495252279Sjkim        PrDbgPrint ("Executing", "else block");
496252279Sjkim        return;
497252279Sjkim
498233237Sjkim    case PR_DIRECTIVE_ELIF:
499250838Sjkim
500252279Sjkim        Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
501252279Sjkim        Directive = PR_DIRECTIVE_IF;
502252279Sjkim
503252279Sjkim        if (Gbl_IgnoringThisCodeBlock == TRUE)
504233237Sjkim        {
505233237Sjkim            /* Not executing the ELSE part -- all done here */
506252279Sjkim            PrDbgPrint ("Ignoring", "elif block");
507233237Sjkim            return;
508233237Sjkim        }
509233237Sjkim
510252279Sjkim        /*
511252279Sjkim         * After this, we will execute the IF part further below.
512252279Sjkim         * First, however, pop off the original #if directive.
513252279Sjkim         */
514252279Sjkim        if (ACPI_FAILURE (PrPopDirective ()))
515252279Sjkim        {
516252279Sjkim            PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
517252279Sjkim                THIS_TOKEN_OFFSET (DirectiveToken));
518252279Sjkim        }
519233237Sjkim
520252279Sjkim        PrDbgPrint ("Executing", "elif block");
521233237Sjkim        break;
522233237Sjkim
523252279Sjkim    case PR_DIRECTIVE_ENDIF:
524250838Sjkim
525252279Sjkim        PrDbgPrint ("Executing", "endif");
526233237Sjkim
527252279Sjkim        /* Pop the owning #if/#ifdef/#ifndef */
528250838Sjkim
529252279Sjkim        if (ACPI_FAILURE (PrPopDirective ()))
530233237Sjkim        {
531233237Sjkim            PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
532233237Sjkim                THIS_TOKEN_OFFSET (DirectiveToken));
533233237Sjkim        }
534233237Sjkim        return;
535233237Sjkim
536233237Sjkim    default:
537233237Sjkim        break;
538233237Sjkim    }
539233237Sjkim
540252279Sjkim    /* Most directives have at least one argument */
541252279Sjkim
542252279Sjkim    if (Gbl_DirectiveInfo[Directive].ArgCount == 1)
543252279Sjkim    {
544252279Sjkim        Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
545252279Sjkim        if (!Token)
546252279Sjkim        {
547252279Sjkim            goto SyntaxError;
548252279Sjkim        }
549252279Sjkim    }
550252279Sjkim
551233237Sjkim    /*
552233237Sjkim     * At this point, if we are ignoring the current code block,
553233237Sjkim     * do not process any more directives (i.e., ignore them also.)
554252279Sjkim     * For "if" style directives, open/push a new block anyway. We
555252279Sjkim     * must do this to keep track of #endif directives
556233237Sjkim     */
557252279Sjkim    if (Gbl_IgnoringThisCodeBlock)
558233237Sjkim    {
559252279Sjkim        switch (Directive)
560252279Sjkim        {
561252279Sjkim        case PR_DIRECTIVE_IF:
562252279Sjkim        case PR_DIRECTIVE_IFDEF:
563252279Sjkim        case PR_DIRECTIVE_IFNDEF:
564252279Sjkim
565252279Sjkim            PrPushDirective (Directive, Token);
566252279Sjkim            PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
567252279Sjkim            break;
568252279Sjkim
569252279Sjkim        default:
570252279Sjkim            break;
571252279Sjkim        }
572252279Sjkim
573233237Sjkim        return;
574233237Sjkim    }
575233237Sjkim
576252279Sjkim    /*
577252279Sjkim     * Execute the directive
578252279Sjkim     */
579252279Sjkim    PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
580233237Sjkim
581252279Sjkim    switch (Directive)
582252279Sjkim    {
583252279Sjkim    case PR_DIRECTIVE_IF:
584233237Sjkim
585252279Sjkim        TokenOffset = Token - Gbl_MainTokenBuffer;
586252279Sjkim
587252279Sjkim        /* Need to expand #define macros in the expression string first */
588252279Sjkim
589252279Sjkim        Status = PrResolveIntegerExpression (
590252279Sjkim            &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
591252279Sjkim        if (ACPI_FAILURE (Status))
592233237Sjkim        {
593252279Sjkim            return;
594233237Sjkim        }
595233237Sjkim
596252279Sjkim        PrPushDirective (Directive, Token);
597252279Sjkim        if (!Value)
598252279Sjkim        {
599252279Sjkim            Gbl_IgnoringThisCodeBlock = TRUE;
600252279Sjkim        }
601252279Sjkim
602252279Sjkim        DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
603252279Sjkim            "Resolved #if: %8.8X%8.8X %s\n",
604252279Sjkim            Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
605252279Sjkim            Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
606252279Sjkim        break;
607252279Sjkim
608252279Sjkim    case PR_DIRECTIVE_IFDEF:
609252279Sjkim
610252279Sjkim        PrPushDirective (Directive, Token);
611252279Sjkim        if (!PrMatchDefine (Token))
612252279Sjkim        {
613252279Sjkim            Gbl_IgnoringThisCodeBlock = TRUE;
614252279Sjkim        }
615252279Sjkim
616252279Sjkim        PrDbgPrint ("Evaluated", "ifdef");
617252279Sjkim        break;
618252279Sjkim
619252279Sjkim    case PR_DIRECTIVE_IFNDEF:
620252279Sjkim
621252279Sjkim        PrPushDirective (Directive, Token);
622252279Sjkim        if (PrMatchDefine (Token))
623252279Sjkim        {
624252279Sjkim            Gbl_IgnoringThisCodeBlock = TRUE;
625252279Sjkim        }
626252279Sjkim
627252279Sjkim        PrDbgPrint ("Evaluated", "ifndef");
628252279Sjkim        break;
629252279Sjkim
630233237Sjkim    case PR_DIRECTIVE_DEFINE:
631233237Sjkim        /*
632233237Sjkim         * By definition, if first char after the name is a paren,
633233237Sjkim         * this is a function macro.
634233237Sjkim         */
635233237Sjkim        TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
636233237Sjkim        if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
637233237Sjkim        {
638233237Sjkim#ifndef MACROS_SUPPORTED
639234623Sjkim            AcpiOsPrintf ("%s ERROR - line %u: #define macros are not supported yet\n",
640234623Sjkim                Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber);
641234623Sjkim            exit(1);
642233237Sjkim#else
643233237Sjkim            PrAddMacro (Token, Next);
644233237Sjkim#endif
645233237Sjkim        }
646233237Sjkim        else
647233237Sjkim        {
648233237Sjkim            /* Use the remainder of the line for the #define */
649233237Sjkim
650233237Sjkim            Token2 = *Next;
651233237Sjkim            if (Token2)
652233237Sjkim            {
653233237Sjkim                while ((*Token2 == ' ') || (*Token2 == '\t'))
654233237Sjkim                {
655233237Sjkim                    Token2++;
656233237Sjkim                }
657233237Sjkim                End = Token2;
658233237Sjkim                while (*End != '\n')
659233237Sjkim                {
660233237Sjkim                    End++;
661233237Sjkim                }
662233237Sjkim                *End = 0;
663233237Sjkim            }
664233237Sjkim            else
665233237Sjkim            {
666233237Sjkim                Token2 = "";
667233237Sjkim            }
668233237Sjkim#if 0
669233237Sjkim            Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
670233237Sjkim            if (!Token2)
671233237Sjkim            {
672233237Sjkim                Token2 = "";
673233237Sjkim            }
674233237Sjkim#endif
675233237Sjkim            DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
676233237Sjkim                "New #define: %s->%s\n",
677233237Sjkim                Gbl_CurrentLineNumber, Token, Token2);
678233237Sjkim
679233237Sjkim            PrAddDefine (Token, Token2, FALSE);
680233237Sjkim        }
681233237Sjkim        break;
682233237Sjkim
683233237Sjkim    case PR_DIRECTIVE_ERROR:
684250838Sjkim
685233237Sjkim        /* Note: No macro expansion */
686233237Sjkim
687233237Sjkim        PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
688233237Sjkim            THIS_TOKEN_OFFSET (Token));
689233237Sjkim
690252279Sjkim        Gbl_SourceLine = 0;
691252279Sjkim        Gbl_NextError = Gbl_ErrorLog;
692252279Sjkim        CmCleanupAndExit ();
693252279Sjkim        exit(1);
694250838Sjkim
695233237Sjkim    case PR_DIRECTIVE_INCLUDE:
696250838Sjkim
697233237Sjkim        Token = PrGetNextToken (NULL, " \"<>", Next);
698233237Sjkim        if (!Token)
699233237Sjkim        {
700233237Sjkim            goto SyntaxError;
701233237Sjkim        }
702233237Sjkim
703233237Sjkim        DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
704235945Sjkim            "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
705233237Sjkim            Token, Gbl_CurrentLineNumber);
706233237Sjkim
707233237Sjkim        PrOpenIncludeFile (Token);
708233237Sjkim        break;
709233237Sjkim
710234623Sjkim    case PR_DIRECTIVE_LINE:
711250838Sjkim
712234623Sjkim        TokenOffset = Token - Gbl_MainTokenBuffer;
713234623Sjkim
714234623Sjkim        Status = PrResolveIntegerExpression (
715234623Sjkim            &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
716234623Sjkim        if (ACPI_FAILURE (Status))
717234623Sjkim        {
718234623Sjkim            return;
719234623Sjkim        }
720234623Sjkim
721234623Sjkim        DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
722234623Sjkim            "User #line invocation %s\n", Gbl_CurrentLineNumber,
723234623Sjkim            Token);
724234623Sjkim
725234623Sjkim        /* Update local line numbers */
726234623Sjkim
727234623Sjkim        Gbl_CurrentLineNumber = (UINT32) Value;
728234623Sjkim        Gbl_PreviousLineNumber = 0;
729234623Sjkim
730234623Sjkim        /* Emit #line into the preprocessor file */
731234623Sjkim
732234623Sjkim        FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
733234623Sjkim            Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
734234623Sjkim        break;
735234623Sjkim
736233237Sjkim    case PR_DIRECTIVE_PRAGMA:
737233237Sjkim
738250838Sjkim        if (!strcmp (Token, "disable"))
739233237Sjkim        {
740250838Sjkim            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
741250838Sjkim            if (!Token)
742250838Sjkim            {
743250838Sjkim                goto SyntaxError;
744250838Sjkim            }
745250838Sjkim
746250838Sjkim            TokenOffset = Token - Gbl_MainTokenBuffer;
747250838Sjkim            AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
748250838Sjkim        }
749250838Sjkim        else if (!strcmp (Token, "message"))
750250838Sjkim        {
751250838Sjkim            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
752250838Sjkim            if (!Token)
753250838Sjkim            {
754250838Sjkim                goto SyntaxError;
755250838Sjkim            }
756250838Sjkim
757250838Sjkim            TokenOffset = Token - Gbl_MainTokenBuffer;
758250838Sjkim            AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
759250838Sjkim        }
760250838Sjkim        else
761250838Sjkim        {
762233237Sjkim            PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
763233237Sjkim                THIS_TOKEN_OFFSET (Token));
764233237Sjkim            return;
765233237Sjkim        }
766233237Sjkim
767233237Sjkim        break;
768233237Sjkim
769233237Sjkim    case PR_DIRECTIVE_UNDEF:
770250838Sjkim
771233237Sjkim        DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
772233237Sjkim            "#undef: %s\n", Gbl_CurrentLineNumber, Token);
773233237Sjkim
774233237Sjkim        PrRemoveDefine (Token);
775233237Sjkim        break;
776233237Sjkim
777233237Sjkim    case PR_DIRECTIVE_WARNING:
778250838Sjkim
779252279Sjkim        PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
780233237Sjkim            THIS_TOKEN_OFFSET (Token));
781233237Sjkim        break;
782233237Sjkim
783233237Sjkim    default:
784250838Sjkim
785233237Sjkim        /* Should never get here */
786233237Sjkim        DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
787233237Sjkim            "Unrecognized directive: %u\n",
788233237Sjkim            Gbl_CurrentLineNumber, Directive);
789233237Sjkim        break;
790233237Sjkim    }
791233237Sjkim
792233237Sjkim    return;
793233237Sjkim
794233237SjkimSyntaxError:
795233237Sjkim
796233237Sjkim    PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
797233237Sjkim        THIS_TOKEN_OFFSET (DirectiveToken));
798233237Sjkim    return;
799233237Sjkim}
800233237Sjkim
801233237Sjkim
802233237Sjkim/*******************************************************************************
803233237Sjkim *
804233237Sjkim * FUNCTION:    PrMatchDirective
805233237Sjkim *
806233237Sjkim * PARAMETERS:  Directive           - Pointer to directive name token
807233237Sjkim *
808233237Sjkim * RETURN:      Index into command array, -1 if not found
809233237Sjkim *
810233237Sjkim * DESCRIPTION: Lookup the incoming directive in the known directives table.
811233237Sjkim *
812233237Sjkim ******************************************************************************/
813233237Sjkim
814233237Sjkimstatic int
815233237SjkimPrMatchDirective (
816233237Sjkim    char                    *Directive)
817233237Sjkim{
818233237Sjkim    int                     i;
819233237Sjkim
820233237Sjkim
821233237Sjkim    if (!Directive || Directive[0] == 0)
822233237Sjkim    {
823233237Sjkim        return (ASL_DIRECTIVE_NOT_FOUND);
824233237Sjkim    }
825233237Sjkim
826233237Sjkim    for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
827233237Sjkim    {
828233237Sjkim        if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
829233237Sjkim        {
830233237Sjkim            return (i);
831233237Sjkim        }
832233237Sjkim    }
833233237Sjkim
834233237Sjkim    return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
835233237Sjkim}
836252279Sjkim
837252279Sjkim
838252279Sjkim/*******************************************************************************
839252279Sjkim *
840252279Sjkim * FUNCTION:    PrPushDirective
841252279Sjkim *
842252279Sjkim * PARAMETERS:  Directive           - Encoded directive ID
843252279Sjkim *              Argument            - String containing argument to the
844252279Sjkim *                                    directive
845252279Sjkim *
846252279Sjkim * RETURN:      None
847252279Sjkim *
848252279Sjkim * DESCRIPTION: Push an item onto the directive stack. Used for processing
849252279Sjkim *              nested #if/#else type conditional compilation directives.
850252279Sjkim *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
851252279Sjkim *              a block.
852252279Sjkim *
853252279Sjkim ******************************************************************************/
854252279Sjkim
855252279Sjkimstatic void
856252279SjkimPrPushDirective (
857252279Sjkim    int                     Directive,
858252279Sjkim    char                    *Argument)
859252279Sjkim{
860252279Sjkim    DIRECTIVE_INFO          *Info;
861252279Sjkim
862252279Sjkim
863252279Sjkim    /* Allocate and populate a stack info item */
864252279Sjkim
865252279Sjkim    Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
866252279Sjkim
867252279Sjkim    Info->Next = Gbl_DirectiveStack;
868252279Sjkim    Info->Directive = Directive;
869252279Sjkim    Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
870252279Sjkim    strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
871252279Sjkim
872252279Sjkim    DbgPrint (ASL_DEBUG_OUTPUT,
873252279Sjkim        "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
874252279Sjkim        Gbl_CurrentLineNumber, Gbl_IfDepth,
875252279Sjkim        Gbl_IgnoringThisCodeBlock ? "I" : "E",
876252279Sjkim        Gbl_IfDepth * 4, " ",
877252279Sjkim        Gbl_DirectiveInfo[Directive].Name,
878252279Sjkim        Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
879252279Sjkim
880252279Sjkim    /* Push new item */
881252279Sjkim
882252279Sjkim    Gbl_DirectiveStack = Info;
883252279Sjkim    Gbl_IfDepth++;
884252279Sjkim}
885252279Sjkim
886252279Sjkim
887252279Sjkim/*******************************************************************************
888252279Sjkim *
889252279Sjkim * FUNCTION:    PrPopDirective
890252279Sjkim *
891252279Sjkim * PARAMETERS:  None
892252279Sjkim *
893252279Sjkim * RETURN:      Status. Error if the stack is empty.
894252279Sjkim *
895252279Sjkim * DESCRIPTION: Pop an item off the directive stack. Used for processing
896252279Sjkim *              nested #if/#else type conditional compilation directives.
897252279Sjkim *              Specifically: Used on detection of #elif and #endif to remove
898252279Sjkim *              the original #if/#ifdef/#ifndef from the stack and close
899252279Sjkim *              the block.
900252279Sjkim *
901252279Sjkim ******************************************************************************/
902252279Sjkim
903252279Sjkimstatic ACPI_STATUS
904252279SjkimPrPopDirective (
905252279Sjkim    void)
906252279Sjkim{
907252279Sjkim    DIRECTIVE_INFO          *Info;
908252279Sjkim
909252279Sjkim
910252279Sjkim    /* Check for empty stack */
911252279Sjkim
912252279Sjkim    Info = Gbl_DirectiveStack;
913252279Sjkim    if (!Info)
914252279Sjkim    {
915252279Sjkim        return (AE_ERROR);
916252279Sjkim    }
917252279Sjkim
918252279Sjkim    /* Pop one item, keep globals up-to-date */
919252279Sjkim
920252279Sjkim    Gbl_IfDepth--;
921252279Sjkim    Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
922252279Sjkim    Gbl_DirectiveStack = Info->Next;
923252279Sjkim
924252279Sjkim    DbgPrint (ASL_DEBUG_OUTPUT,
925252279Sjkim        "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
926252279Sjkim        Gbl_CurrentLineNumber, Gbl_IfDepth,
927252279Sjkim        Gbl_IgnoringThisCodeBlock ? "I" : "E",
928252279Sjkim        Gbl_IfDepth * 4, " ",
929252279Sjkim        Gbl_DirectiveInfo[Info->Directive].Name,
930252279Sjkim        Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
931252279Sjkim
932252279Sjkim    ACPI_FREE (Info);
933252279Sjkim    return (AE_OK);
934252279Sjkim}
935252279Sjkim
936252279Sjkim
937252279Sjkim/*******************************************************************************
938252279Sjkim *
939252279Sjkim * FUNCTION:    PrDbgPrint
940252279Sjkim *
941252279Sjkim * PARAMETERS:  Action              - Action being performed
942252279Sjkim *              DirectiveName       - Directive being processed
943252279Sjkim *
944252279Sjkim * RETURN:      None
945252279Sjkim *
946252279Sjkim * DESCRIPTION: Special debug print for directive processing.
947252279Sjkim *
948252279Sjkim ******************************************************************************/
949252279Sjkim
950252279Sjkimstatic void
951252279SjkimPrDbgPrint (
952252279Sjkim    char                    *Action,
953252279Sjkim    char                    *DirectiveName)
954252279Sjkim{
955252279Sjkim
956252279Sjkim    DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
957252279Sjkim        "%*s %s #%s, Depth %u\n",
958252279Sjkim        Gbl_CurrentLineNumber, Gbl_IfDepth,
959252279Sjkim        Gbl_IgnoringThisCodeBlock ? "I" : "E",
960252279Sjkim        Gbl_IfDepth * 4, " ",
961252279Sjkim        Action, DirectiveName, Gbl_IfDepth);
962252279Sjkim}
963