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