1 /******************************************************************************
3 * Module Name: prscan - Preprocessor start-up and file scan module
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
44 #define _DECLARE_PR_GLOBALS
46 #include "aslcompiler.h"
47 #include "dtcompiler.h"
52 * No nested macros, maybe never
53 * Implement ASL "Include" as well as "#include" here?
55 #define _COMPONENT ASL_PREPROCESSOR
56 ACPI_MODULE_NAME ("prscan")
59 /* Local prototypes */
62 PrPreprocessInputFile (
90 * Supported preprocessor directives
92 static const PR_DIRECTIVE_INFO Gbl_DirectiveInfo
[] =
95 {"elif", 0}, /* Converted to #else..#if internally */
102 {"include", 0}, /* Argument is not standard format, so 0 */
110 enum Gbl_DirectiveIndexes
112 PR_DIRECTIVE_DEFINE
= 0,
120 PR_DIRECTIVE_INCLUDE
,
124 PR_DIRECTIVE_WARNING
,
127 #define ASL_DIRECTIVE_NOT_FOUND -1
130 /*******************************************************************************
132 * FUNCTION: PrInitializePreprocessor
138 * DESCRIPTION: Startup initialization for the Preprocessor.
140 ******************************************************************************/
143 PrInitializePreprocessor (
146 /* Init globals and the list of #defines */
148 PrInitializeGlobals ();
149 Gbl_DefineList
= NULL
;
153 /*******************************************************************************
155 * FUNCTION: PrInitializeGlobals
161 * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup
162 * initialization and re-initialization between compiles during
163 * a multiple source file compile.
165 ******************************************************************************/
168 PrInitializeGlobals (
173 Gbl_InputFileList
= NULL
;
174 Gbl_CurrentLineNumber
= 0;
175 Gbl_PreprocessorLineNumber
= 1;
176 Gbl_PreprocessorError
= FALSE
;
178 /* These are used to track #if/#else blocks (possibly nested) */
181 Gbl_IgnoringThisCodeBlock
= FALSE
;
182 Gbl_DirectiveStack
= NULL
;
186 /*******************************************************************************
188 * FUNCTION: PrTerminatePreprocessor
194 * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any
195 * defines that were specified on the command line, in order to
196 * support multiple compiles with a single compiler invocation.
198 ******************************************************************************/
201 PrTerminatePreprocessor (
204 PR_DEFINE_INFO
*DefineInfo
;
208 * The persistent defines (created on the command line) are always at the
209 * end of the list. We save them.
211 while ((Gbl_DefineList
) && (!Gbl_DefineList
->Persist
))
213 DefineInfo
= Gbl_DefineList
;
214 Gbl_DefineList
= DefineInfo
->Next
;
216 ACPI_FREE (DefineInfo
->Replacement
);
217 ACPI_FREE (DefineInfo
->Identifier
);
218 ACPI_FREE (DefineInfo
);
223 /*******************************************************************************
225 * FUNCTION: PrDoPreprocess
231 * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must
232 * be already open. Handles multiple input files via the
233 * #include directive.
235 ******************************************************************************/
241 BOOLEAN MoreInputFiles
;
244 DbgPrint (ASL_DEBUG_OUTPUT
, "Starting preprocessing phase\n\n");
247 FlSeekFile (ASL_FILE_INPUT
, 0);
248 PrDumpPredefinedNames ();
250 /* Main preprocessor loop, handles include files */
254 PrPreprocessInputFile ();
255 MoreInputFiles
= PrPopInputFileStack ();
257 } while (MoreInputFiles
);
259 /* Point compiler input to the new preprocessor output file (.i) */
261 FlCloseFile (ASL_FILE_INPUT
);
262 Gbl_Files
[ASL_FILE_INPUT
].Handle
= Gbl_Files
[ASL_FILE_PREPROCESSOR
].Handle
;
263 AslCompilerin
= Gbl_Files
[ASL_FILE_INPUT
].Handle
;
265 /* Reset globals to allow compiler to run */
267 FlSeekFile (ASL_FILE_INPUT
, 0);
268 Gbl_CurrentLineNumber
= 1;
270 DbgPrint (ASL_DEBUG_OUTPUT
, "Preprocessing phase complete \n\n");
274 /*******************************************************************************
276 * FUNCTION: PrPreprocessInputFile
282 * DESCRIPTION: Preprocess one entire file, line-by-line.
284 * Input: Raw user ASL from ASL_FILE_INPUT
285 * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR
287 ******************************************************************************/
290 PrPreprocessInputFile (
296 PR_DEFINE_INFO
*DefineInfo
;
297 ACPI_SIZE TokenOffset
;
302 /* Scan line-by-line. Comments and blank lines are skipped by this function */
304 while ((Offset
= DtGetNextLine (Gbl_Files
[ASL_FILE_INPUT
].Handle
)) != ASL_EOF
)
306 /* Need a copy of the input line for strok() */
308 strcpy (Gbl_MainTokenBuffer
, Gbl_CurrentLineBuffer
);
309 Token
= PrGetNextToken (Gbl_MainTokenBuffer
, PR_TOKEN_SEPARATORS
, &Next
);
312 /* All preprocessor directives must begin with '#' */
314 if (Token
&& (*Token
== '#'))
316 if (strlen (Token
) == 1)
318 Token
= PrGetNextToken (NULL
, PR_TOKEN_SEPARATORS
, &Next
);
322 Token
++; /* Skip leading # */
325 /* Execute the directive, do not write line to output file */
327 PrDoDirective (Token
, &Next
);
332 * If we are currently within the part of an IF/ELSE block that is
333 * FALSE, ignore the line and do not write it to the output file.
334 * This continues until an #else or #endif is encountered.
336 if (Gbl_IgnoringThisCodeBlock
)
341 /* Match and replace all #defined names within this source line */
345 DefineInfo
= PrMatchDefine (Token
);
348 if (DefineInfo
->Body
)
350 /* This is a macro */
352 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
353 "Matched Macro: %s->%s\n",
354 Gbl_CurrentLineNumber
, DefineInfo
->Identifier
,
355 DefineInfo
->Replacement
);
357 PrDoMacroInvocation (Gbl_MainTokenBuffer
, Token
,
362 ReplaceString
= DefineInfo
->Replacement
;
364 /* Replace the name in the original line buffer */
366 TokenOffset
= Token
- Gbl_MainTokenBuffer
+ OffsetAdjust
;
368 &Gbl_CurrentLineBuffer
[TokenOffset
], strlen (Token
),
369 ReplaceString
, strlen (ReplaceString
));
371 /* Adjust for length difference between old and new name length */
373 OffsetAdjust
+= strlen (ReplaceString
) - strlen (Token
);
375 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
376 "Matched #define: %s->%s\n",
377 Gbl_CurrentLineNumber
, Token
,
378 *ReplaceString
? ReplaceString
: "(NULL STRING)");
382 Token
= PrGetNextToken (NULL
, PR_TOKEN_SEPARATORS
, &Next
);
387 FlPrintFile (ASL_FILE_PREPROCESSOR
, "/* %14s %.5u i:%.5u */ ",
388 Gbl_Files
[ASL_FILE_INPUT
].Filename
,
389 Gbl_CurrentLineNumber
, Gbl_PreprocessorLineNumber
);
393 * Emit a #line directive if necessary, to keep the line numbers in
394 * the (.i) file synchronized with the original source code file, so
395 * that the correct line number appears in any error messages
396 * generated by the actual compiler.
398 if (Gbl_CurrentLineNumber
> (Gbl_PreviousLineNumber
+ 1))
400 FlPrintFile (ASL_FILE_PREPROCESSOR
, "#line %u\n",
401 Gbl_CurrentLineNumber
);
404 Gbl_PreviousLineNumber
= Gbl_CurrentLineNumber
;
405 Gbl_PreprocessorLineNumber
++;
408 * Now we can write the possibly modified source line to the
409 * preprocessor (.i) file
411 FlWriteFile (ASL_FILE_PREPROCESSOR
, Gbl_CurrentLineBuffer
,
412 strlen (Gbl_CurrentLineBuffer
));
417 /*******************************************************************************
419 * FUNCTION: PrDoDirective
421 * PARAMETERS: Directive - Pointer to directive name token
422 * Next - "Next" buffer from GetNextToken
426 * DESCRIPTION: Main processing for all preprocessor directives
428 ******************************************************************************/
432 char *DirectiveToken
,
435 char *Token
= Gbl_MainTokenBuffer
;
439 ACPI_SIZE TokenOffset
;
449 Directive
= PrMatchDirective (DirectiveToken
);
450 if (Directive
== ASL_DIRECTIVE_NOT_FOUND
)
452 PrError (ASL_ERROR
, ASL_MSG_UNKNOWN_DIRECTIVE
,
453 THIS_TOKEN_OFFSET (DirectiveToken
));
455 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
456 "#%s: Unknown directive\n",
457 Gbl_CurrentLineNumber
, DirectiveToken
);
462 * If we are currently ignoring this block and we encounter a #else or
463 * #elif, we must ignore their blocks also if the parent block is also
466 if (Gbl_IgnoringThisCodeBlock
)
470 case PR_DIRECTIVE_ELSE
:
471 case PR_DIRECTIVE_ELIF
:
473 if (Gbl_DirectiveStack
&& Gbl_DirectiveStack
->IgnoringThisCodeBlock
)
475 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo
[Directive
].Name
);
486 * Need to always check for #else, #elif, #endif regardless of
487 * whether we are ignoring the current code block, since these
488 * are conditional code block terminators.
492 case PR_DIRECTIVE_ELSE
:
494 Gbl_IgnoringThisCodeBlock
= !(Gbl_IgnoringThisCodeBlock
);
495 PrDbgPrint ("Executing", "else block");
498 case PR_DIRECTIVE_ELIF
:
500 Gbl_IgnoringThisCodeBlock
= !(Gbl_IgnoringThisCodeBlock
);
501 Directive
= PR_DIRECTIVE_IF
;
503 if (Gbl_IgnoringThisCodeBlock
== TRUE
)
505 /* Not executing the ELSE part -- all done here */
506 PrDbgPrint ("Ignoring", "elif block");
511 * After this, we will execute the IF part further below.
512 * First, however, pop off the original #if directive.
514 if (ACPI_FAILURE (PrPopDirective ()))
516 PrError (ASL_ERROR
, ASL_MSG_COMPILER_INTERNAL
,
517 THIS_TOKEN_OFFSET (DirectiveToken
));
520 PrDbgPrint ("Executing", "elif block");
523 case PR_DIRECTIVE_ENDIF
:
525 PrDbgPrint ("Executing", "endif");
527 /* Pop the owning #if/#ifdef/#ifndef */
529 if (ACPI_FAILURE (PrPopDirective ()))
531 PrError (ASL_ERROR
, ASL_MSG_ENDIF_MISMATCH
,
532 THIS_TOKEN_OFFSET (DirectiveToken
));
540 /* Most directives have at least one argument */
542 if (Gbl_DirectiveInfo
[Directive
].ArgCount
== 1)
544 Token
= PrGetNextToken (NULL
, PR_TOKEN_SEPARATORS
, Next
);
552 * At this point, if we are ignoring the current code block,
553 * do not process any more directives (i.e., ignore them also.)
554 * For "if" style directives, open/push a new block anyway. We
555 * must do this to keep track of #endif directives
557 if (Gbl_IgnoringThisCodeBlock
)
561 case PR_DIRECTIVE_IF
:
562 case PR_DIRECTIVE_IFDEF
:
563 case PR_DIRECTIVE_IFNDEF
:
565 PrPushDirective (Directive
, Token
);
566 PrDbgPrint ("Ignoring", Gbl_DirectiveInfo
[Directive
].Name
);
577 * Execute the directive
579 PrDbgPrint ("Begin execution", Gbl_DirectiveInfo
[Directive
].Name
);
583 case PR_DIRECTIVE_IF
:
585 TokenOffset
= Token
- Gbl_MainTokenBuffer
;
587 /* Need to expand #define macros in the expression string first */
589 Status
= PrResolveIntegerExpression (
590 &Gbl_CurrentLineBuffer
[TokenOffset
-1], &Value
);
591 if (ACPI_FAILURE (Status
))
596 PrPushDirective (Directive
, Token
);
599 Gbl_IgnoringThisCodeBlock
= TRUE
;
602 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
603 "Resolved #if: %8.8X%8.8X %s\n",
604 Gbl_CurrentLineNumber
, ACPI_FORMAT_UINT64 (Value
),
605 Gbl_IgnoringThisCodeBlock
? "<Skipping Block>" : "<Executing Block>");
608 case PR_DIRECTIVE_IFDEF
:
610 PrPushDirective (Directive
, Token
);
611 if (!PrMatchDefine (Token
))
613 Gbl_IgnoringThisCodeBlock
= TRUE
;
616 PrDbgPrint ("Evaluated", "ifdef");
619 case PR_DIRECTIVE_IFNDEF
:
621 PrPushDirective (Directive
, Token
);
622 if (PrMatchDefine (Token
))
624 Gbl_IgnoringThisCodeBlock
= TRUE
;
627 PrDbgPrint ("Evaluated", "ifndef");
630 case PR_DIRECTIVE_DEFINE
:
632 * By definition, if first char after the name is a paren,
633 * this is a function macro.
635 TokenOffset
= Token
- Gbl_MainTokenBuffer
+ strlen (Token
);
636 if (*(&Gbl_CurrentLineBuffer
[TokenOffset
]) == '(')
638 #ifndef MACROS_SUPPORTED
639 AcpiOsPrintf ("%s ERROR - line %u: #define macros are not supported yet\n",
640 Gbl_CurrentLineBuffer
, Gbl_CurrentLineNumber
);
643 PrAddMacro (Token
, Next
);
648 /* Use the remainder of the line for the #define */
653 while ((*Token2
== ' ') || (*Token2
== '\t'))
669 Token2
= PrGetNextToken (NULL
, "\n", /*PR_TOKEN_SEPARATORS,*/ Next
);
675 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
676 "New #define: %s->%s\n",
677 Gbl_CurrentLineNumber
, Token
, Token2
);
679 PrAddDefine (Token
, Token2
, FALSE
);
683 case PR_DIRECTIVE_ERROR
:
685 /* Note: No macro expansion */
687 PrError (ASL_ERROR
, ASL_MSG_ERROR_DIRECTIVE
,
688 THIS_TOKEN_OFFSET (Token
));
691 Gbl_NextError
= Gbl_ErrorLog
;
695 case PR_DIRECTIVE_INCLUDE
:
697 Token
= PrGetNextToken (NULL
, " \"<>", Next
);
703 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
704 "Start #include file \"%s\"\n", Gbl_CurrentLineNumber
,
705 Token
, Gbl_CurrentLineNumber
);
707 PrOpenIncludeFile (Token
);
710 case PR_DIRECTIVE_LINE
:
712 TokenOffset
= Token
- Gbl_MainTokenBuffer
;
714 Status
= PrResolveIntegerExpression (
715 &Gbl_CurrentLineBuffer
[TokenOffset
-1], &Value
);
716 if (ACPI_FAILURE (Status
))
721 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
722 "User #line invocation %s\n", Gbl_CurrentLineNumber
,
725 /* Update local line numbers */
727 Gbl_CurrentLineNumber
= (UINT32
) Value
;
728 Gbl_PreviousLineNumber
= 0;
730 /* Emit #line into the preprocessor file */
732 FlPrintFile (ASL_FILE_PREPROCESSOR
, "#line %u \"%s\"\n",
733 Gbl_CurrentLineNumber
, Gbl_Files
[ASL_FILE_INPUT
].Filename
);
736 case PR_DIRECTIVE_PRAGMA
:
738 if (!strcmp (Token
, "disable"))
740 Token
= PrGetNextToken (NULL
, PR_TOKEN_SEPARATORS
, Next
);
746 TokenOffset
= Token
- Gbl_MainTokenBuffer
;
747 AslDisableException (&Gbl_CurrentLineBuffer
[TokenOffset
]);
749 else if (!strcmp (Token
, "message"))
751 Token
= PrGetNextToken (NULL
, PR_TOKEN_SEPARATORS
, Next
);
757 TokenOffset
= Token
- Gbl_MainTokenBuffer
;
758 AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer
[TokenOffset
]);
762 PrError (ASL_ERROR
, ASL_MSG_UNKNOWN_PRAGMA
,
763 THIS_TOKEN_OFFSET (Token
));
769 case PR_DIRECTIVE_UNDEF
:
771 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
772 "#undef: %s\n", Gbl_CurrentLineNumber
, Token
);
774 PrRemoveDefine (Token
);
777 case PR_DIRECTIVE_WARNING
:
779 PrError (ASL_WARNING
, ASL_MSG_WARNING_DIRECTIVE
,
780 THIS_TOKEN_OFFSET (Token
));
785 /* Should never get here */
786 DbgPrint (ASL_DEBUG_OUTPUT
, PR_PREFIX_ID
787 "Unrecognized directive: %u\n",
788 Gbl_CurrentLineNumber
, Directive
);
796 PrError (ASL_ERROR
, ASL_MSG_DIRECTIVE_SYNTAX
,
797 THIS_TOKEN_OFFSET (DirectiveToken
));
802 /*******************************************************************************
804 * FUNCTION: PrMatchDirective
806 * PARAMETERS: Directive - Pointer to directive name token
808 * RETURN: Index into command array, -1 if not found
810 * DESCRIPTION: Lookup the incoming directive in the known directives table.
812 ******************************************************************************/
821 if (!Directive
|| Directive
[0] == 0)
823 return (ASL_DIRECTIVE_NOT_FOUND
);
826 for (i
= 0; Gbl_DirectiveInfo
[i
].Name
; i
++)
828 if (!strcmp (Gbl_DirectiveInfo
[i
].Name
, Directive
))
834 return (ASL_DIRECTIVE_NOT_FOUND
); /* Command not recognized */
838 /*******************************************************************************
840 * FUNCTION: PrPushDirective
842 * PARAMETERS: Directive - Encoded directive ID
843 * Argument - String containing argument to the
848 * DESCRIPTION: Push an item onto the directive stack. Used for processing
849 * nested #if/#else type conditional compilation directives.
850 * Specifically: Used on detection of #if/#ifdef/#ifndef to open
853 ******************************************************************************/
860 DIRECTIVE_INFO
*Info
;
863 /* Allocate and populate a stack info item */
865 Info
= ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO
));
867 Info
->Next
= Gbl_DirectiveStack
;
868 Info
->Directive
= Directive
;
869 Info
->IgnoringThisCodeBlock
= Gbl_IgnoringThisCodeBlock
;
870 strncpy (Info
->Argument
, Argument
, MAX_ARGUMENT_LENGTH
);
872 DbgPrint (ASL_DEBUG_OUTPUT
,
873 "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
874 Gbl_CurrentLineNumber
, Gbl_IfDepth
,
875 Gbl_IgnoringThisCodeBlock
? "I" : "E",
876 Gbl_IfDepth
* 4, " ",
877 Gbl_DirectiveInfo
[Directive
].Name
,
878 Argument
, Gbl_IgnoringThisCodeBlock
? "TRUE" : "FALSE");
882 Gbl_DirectiveStack
= Info
;
887 /*******************************************************************************
889 * FUNCTION: PrPopDirective
893 * RETURN: Status. Error if the stack is empty.
895 * DESCRIPTION: Pop an item off the directive stack. Used for processing
896 * nested #if/#else type conditional compilation directives.
897 * Specifically: Used on detection of #elif and #endif to remove
898 * the original #if/#ifdef/#ifndef from the stack and close
901 ******************************************************************************/
907 DIRECTIVE_INFO
*Info
;
910 /* Check for empty stack */
912 Info
= Gbl_DirectiveStack
;
918 /* Pop one item, keep globals up-to-date */
921 Gbl_IgnoringThisCodeBlock
= Info
->IgnoringThisCodeBlock
;
922 Gbl_DirectiveStack
= Info
->Next
;
924 DbgPrint (ASL_DEBUG_OUTPUT
,
925 "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
926 Gbl_CurrentLineNumber
, Gbl_IfDepth
,
927 Gbl_IgnoringThisCodeBlock
? "I" : "E",
928 Gbl_IfDepth
* 4, " ",
929 Gbl_DirectiveInfo
[Info
->Directive
].Name
,
930 Info
->Argument
, Gbl_IgnoringThisCodeBlock
? "TRUE" : "FALSE");
937 /*******************************************************************************
939 * FUNCTION: PrDbgPrint
941 * PARAMETERS: Action - Action being performed
942 * DirectiveName - Directive being processed
946 * DESCRIPTION: Special debug print for directive processing.
948 ******************************************************************************/
956 DbgPrint (ASL_DEBUG_OUTPUT
, "Pr(%.4u) - [%u %s] "
957 "%*s %s #%s, Depth %u\n",
958 Gbl_CurrentLineNumber
, Gbl_IfDepth
,
959 Gbl_IgnoringThisCodeBlock
? "I" : "E",
960 Gbl_IfDepth
* 4, " ",
961 Action
, DirectiveName
, Gbl_IfDepth
);