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