1 /******************************************************************************
2 *
3 * Module Name: prscan - Preprocessor start-up and file scan module
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2022, 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 #ifndef MACROS_SUPPORTED
676 AcpiOsPrintf (
677 "%s ERROR - line %u: #define macros are not supported yet\n",
678 AslGbl_CurrentLineBuffer, AslGbl_LogicalLineNumber);
679 exit(1);
680 #else
681 PrAddMacro (Token, Next);
682 #endif
683 }
684 else
685 {
686 /* Use the remainder of the line for the #define */
687
688 Token2 = *Next;
689 if (Token2)
690 {
691 while ((*Token2 == ' ') || (*Token2 == '\t'))
692 {
693 Token2++;
694 }
695
696 End = Token2;
697 while (*End != '\n')
698 {
699 End++;
700 }
701
702 *End = 0;
703 }
704 else
705 {
706 Token2 = "";
707 }
708 #if 0
709 Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
710 if (!Token2)
711 {
712 Token2 = "";
713 }
714 #endif
715 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
716 "New #define: %s->%s\n",
717 AslGbl_LogicalLineNumber, Token, Token2);
718
719 PrAddDefine (Token, Token2, FALSE);
720 }
721 break;
722
723 case PR_DIRECTIVE_ERROR:
724
725 /* Note: No macro expansion */
726
727 PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
728 THIS_TOKEN_OFFSET (Token));
729
730 AslGbl_SourceLine = 0;
731 AslGbl_NextError = AslGbl_ErrorLog;
732 CmCleanupAndExit ();
733 exit(1);
734
735 case PR_DIRECTIVE_INCLUDE:
736
737 Token = PrGetNextToken (NULL, " \"<>", Next);
738 if (!Token)
739 {
740 goto SyntaxError;
741 }
742
743 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
744 "Start #include file \"%s\"\n", AslGbl_CurrentLineNumber,
745 Token);
746
747 PrDoIncludeFile (Token);
748 break;
749
750 case PR_DIRECTIVE_INCLUDEBUFFER:
751
752 Token = PrGetNextToken (NULL, " \"<>", Next);
753 if (!Token)
754 {
755 goto SyntaxError;
756 }
757
758 Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
759 if (!Token2)
760 {
761 goto SyntaxError;
762 }
763
764 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
765 "Start #includebuffer input from file \"%s\", buffer name %s\n",
766 AslGbl_CurrentLineNumber, Token, Token2);
767
768 PrDoIncludeBuffer (Token, Token2);
769 break;
770
771 case PR_DIRECTIVE_LINE:
772
773 TokenOffset = Token - AslGbl_MainTokenBuffer;
774
775 Status = PrResolveIntegerExpression (
776 &AslGbl_CurrentLineBuffer[TokenOffset-1], &Value);
777 if (ACPI_FAILURE (Status))
778 {
779 return;
780 }
781
782 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
783 "User #line invocation %s\n", AslGbl_CurrentLineNumber,
784 Token);
785
786 AslGbl_CurrentLineNumber = (UINT32) Value;
787
788 /* Emit #line into the preprocessor file */
789
790 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
791 AslGbl_CurrentLineNumber, AslGbl_Files[ASL_FILE_INPUT].Filename);
792 break;
793
794 case PR_DIRECTIVE_PRAGMA:
795
796 if (!strcmp (Token, "disable"))
797 {
798 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
799 if (!Token)
800 {
801 goto SyntaxError;
802 }
803
804 TokenOffset = Token - AslGbl_MainTokenBuffer;
805 AslDisableException (&AslGbl_CurrentLineBuffer[TokenOffset]);
806 }
807 else if (!strcmp (Token, "message"))
808 {
809 Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
810 if (!Token)
811 {
812 goto SyntaxError;
813 }
814
815 TokenOffset = Token - AslGbl_MainTokenBuffer;
816 AcpiOsPrintf ("%s\n", &AslGbl_CurrentLineBuffer[TokenOffset]);
817 }
818 else
819 {
820 PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
821 THIS_TOKEN_OFFSET (Token));
822 return;
823 }
824
825 break;
826
827 case PR_DIRECTIVE_UNDEF:
828
829 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
830 "#undef: %s\n", AslGbl_CurrentLineNumber, Token);
831
832 PrRemoveDefine (Token);
833 break;
834
835 case PR_DIRECTIVE_WARNING:
836
837 PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
838 THIS_TOKEN_OFFSET (Token));
839
840 AslGbl_SourceLine = 0;
841 AslGbl_NextError = AslGbl_ErrorLog;
842 break;
843
844 default:
845
846 /* Should never get here */
847 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
848 "Unrecognized directive: %u\n",
849 AslGbl_CurrentLineNumber, Directive);
850 break;
851 }
852
853 return;
854
855 SyntaxError:
856
857 PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
858 THIS_TOKEN_OFFSET (DirectiveToken));
859 return;
860 }
861
862
863 /*******************************************************************************
864 *
865 * FUNCTION: PrGetNextLine, PrGetNextLineInit
866 *
867 * PARAMETERS: Handle - Open file handle for the source file
868 *
869 * RETURN: Status of the GetLine operation:
870 * AE_OK - Normal line, OK status
871 * ASL_IGNORE_LINE - Line is blank or part of a multi-line
872 * comment
873 * ASL_EOF - End-of-file reached
874 *
875 * DESCRIPTION: Get the next text line from the input file. Does not strip
876 * comments.
877 *
878 ******************************************************************************/
879
880 #define PR_NORMAL_TEXT 0
881 #define PR_MULTI_LINE_COMMENT 1
882 #define PR_SINGLE_LINE_COMMENT 2
883 #define PR_QUOTED_STRING 3
884
885 static UINT8 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
886
887 static void
PrGetNextLineInit(void)888 PrGetNextLineInit (
889 void)
890 {
891 AcpiGbl_LineScanState = 0;
892 }
893
894 static UINT32
PrGetNextLine(FILE * Handle)895 PrGetNextLine (
896 FILE *Handle)
897 {
898 UINT32 i;
899 int c = 0;
900 int PreviousChar;
901
902
903 /* Always clear the global line buffer */
904
905 memset (AslGbl_CurrentLineBuffer, 0, AslGbl_LineBufferSize);
906 for (i = 0; ;)
907 {
908 /*
909 * If line is too long, expand the line buffers. Also increases
910 * AslGbl_LineBufferSize.
911 */
912 if (i >= AslGbl_LineBufferSize)
913 {
914 UtExpandLineBuffers ();
915 }
916
917 PreviousChar = c;
918 c = getc (Handle);
919 if (c == EOF)
920 {
921 /*
922 * On EOF: If there is anything in the line buffer, terminate
923 * it with a newline, and catch the EOF on the next call
924 * to this function.
925 */
926 if (i > 0)
927 {
928 AslGbl_CurrentLineBuffer[i] = '\n';
929 return (AE_OK);
930 }
931
932 return (ASL_EOF);
933 }
934
935 /* Update state machine as necessary */
936
937 switch (AcpiGbl_LineScanState)
938 {
939 case PR_NORMAL_TEXT:
940
941 /* Check for multi-line comment start */
942
943 if ((PreviousChar == '/') && (c == '*'))
944 {
945 AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT;
946 }
947
948 /* Check for single-line comment start */
949
950 else if ((PreviousChar == '/') && (c == '/'))
951 {
952 AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT;
953 }
954
955 /* Check for quoted string start */
956
957 else if (PreviousChar == '"')
958 {
959 AcpiGbl_LineScanState = PR_QUOTED_STRING;
960 }
961 break;
962
963 case PR_QUOTED_STRING:
964
965 if (PreviousChar == '"')
966 {
967 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
968 }
969 break;
970
971 case PR_MULTI_LINE_COMMENT:
972
973 /* Check for multi-line comment end */
974
975 if ((PreviousChar == '*') && (c == '/'))
976 {
977 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
978 }
979 break;
980
981 case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */
982 default:
983 break;
984 }
985
986 /* Always copy the character into line buffer */
987
988 AslGbl_CurrentLineBuffer[i] = (char) c;
989 i++;
990
991 /* Always exit on end-of-line */
992
993 if (c == '\n')
994 {
995 /* Handle multi-line comments */
996
997 if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT)
998 {
999 return (ASL_IGNORE_LINE);
1000 }
1001
1002 /* End of single-line comment */
1003
1004 if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT)
1005 {
1006 AcpiGbl_LineScanState = PR_NORMAL_TEXT;
1007 return (AE_OK);
1008 }
1009
1010 /* Blank line */
1011
1012 if (i == 1)
1013 {
1014 return (ASL_IGNORE_LINE);
1015 }
1016
1017 return (AE_OK);
1018 }
1019 }
1020 }
1021
1022
1023 /*******************************************************************************
1024 *
1025 * FUNCTION: PrMatchDirective
1026 *
1027 * PARAMETERS: Directive - Pointer to directive name token
1028 *
1029 * RETURN: Index into command array, -1 if not found
1030 *
1031 * DESCRIPTION: Lookup the incoming directive in the known directives table.
1032 *
1033 ******************************************************************************/
1034
1035 static int
PrMatchDirective(char * Directive)1036 PrMatchDirective (
1037 char *Directive)
1038 {
1039 int i;
1040
1041
1042 if (!Directive || Directive[0] == 0)
1043 {
1044 return (ASL_DIRECTIVE_NOT_FOUND);
1045 }
1046
1047 for (i = 0; AslGbl_DirectiveInfo[i].Name; i++)
1048 {
1049 if (!strcmp (AslGbl_DirectiveInfo[i].Name, Directive))
1050 {
1051 return (i);
1052 }
1053 }
1054
1055 return (ASL_DIRECTIVE_NOT_FOUND); /* Command not recognized */
1056 }
1057
1058
1059 /*******************************************************************************
1060 *
1061 * FUNCTION: PrPushDirective
1062 *
1063 * PARAMETERS: Directive - Encoded directive ID
1064 * Argument - String containing argument to the
1065 * directive
1066 *
1067 * RETURN: None
1068 *
1069 * DESCRIPTION: Push an item onto the directive stack. Used for processing
1070 * nested #if/#else type conditional compilation directives.
1071 * Specifically: Used on detection of #if/#ifdef/#ifndef to open
1072 * a block.
1073 *
1074 ******************************************************************************/
1075
1076 static void
PrPushDirective(int Directive,char * Argument)1077 PrPushDirective (
1078 int Directive,
1079 char *Argument)
1080 {
1081 DIRECTIVE_INFO *Info;
1082
1083
1084 /* Allocate and populate a stack info item */
1085
1086 Info = ACPI_CAST_PTR (DIRECTIVE_INFO,
1087 UtLocalCacheCalloc (sizeof (DIRECTIVE_INFO)));
1088
1089 Info->Next = AslGbl_DirectiveStack;
1090 Info->Directive = Directive;
1091 Info->IgnoringThisCodeBlock = AslGbl_IgnoringThisCodeBlock;
1092 AcpiUtSafeStrncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
1093
1094 DbgPrint (ASL_DEBUG_OUTPUT,
1095 "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
1096 AslGbl_CurrentLineNumber, AslGbl_IfDepth,
1097 AslGbl_IgnoringThisCodeBlock ? "I" : "E",
1098 AslGbl_IfDepth * 4, " ",
1099 AslGbl_DirectiveInfo[Directive].Name,
1100 Argument, AslGbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1101
1102 /* Push new item */
1103
1104 AslGbl_DirectiveStack = Info;
1105 AslGbl_IfDepth++;
1106 }
1107
1108
1109 /*******************************************************************************
1110 *
1111 * FUNCTION: PrPopDirective
1112 *
1113 * PARAMETERS: None
1114 *
1115 * RETURN: Status. Error if the stack is empty.
1116 *
1117 * DESCRIPTION: Pop an item off the directive stack. Used for processing
1118 * nested #if/#else type conditional compilation directives.
1119 * Specifically: Used on detection of #elif and #endif to remove
1120 * the original #if/#ifdef/#ifndef from the stack and close
1121 * the block.
1122 *
1123 ******************************************************************************/
1124
1125 static ACPI_STATUS
PrPopDirective(void)1126 PrPopDirective (
1127 void)
1128 {
1129 DIRECTIVE_INFO *Info;
1130
1131
1132 /* Check for empty stack */
1133
1134 Info = AslGbl_DirectiveStack;
1135 if (!Info)
1136 {
1137 return (AE_ERROR);
1138 }
1139
1140 /* Pop one item, keep globals up-to-date */
1141
1142 AslGbl_IfDepth--;
1143 AslGbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
1144 AslGbl_DirectiveStack = Info->Next;
1145
1146 DbgPrint (ASL_DEBUG_OUTPUT,
1147 "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
1148 AslGbl_CurrentLineNumber, AslGbl_IfDepth,
1149 AslGbl_IgnoringThisCodeBlock ? "I" : "E",
1150 AslGbl_IfDepth * 4, " ",
1151 AslGbl_DirectiveInfo[Info->Directive].Name,
1152 Info->Argument, AslGbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
1153
1154 return (AE_OK);
1155 }
1156
1157
1158 /*******************************************************************************
1159 *
1160 * FUNCTION: PrDbgPrint
1161 *
1162 * PARAMETERS: Action - Action being performed
1163 * DirectiveName - Directive being processed
1164 *
1165 * RETURN: None
1166 *
1167 * DESCRIPTION: Special debug print for directive processing.
1168 *
1169 ******************************************************************************/
1170
1171 static void
PrDbgPrint(char * Action,char * DirectiveName)1172 PrDbgPrint (
1173 char *Action,
1174 char *DirectiveName)
1175 {
1176
1177 DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
1178 "%*s %s #%s, IfDepth %u\n",
1179 AslGbl_CurrentLineNumber, AslGbl_IfDepth,
1180 AslGbl_IgnoringThisCodeBlock ? "I" : "E",
1181 AslGbl_IfDepth * 4, " ",
1182 Action, DirectiveName, AslGbl_IfDepth);
1183 }
1184
1185
1186 /*******************************************************************************
1187 *
1188 * FUNCTION: PrDoIncludeFile
1189 *
1190 * PARAMETERS: Pathname - Name of the input file
1191 *
1192 * RETURN: None.
1193 *
1194 * DESCRIPTION: Open an include file, from #include.
1195 *
1196 ******************************************************************************/
1197
1198 static void
PrDoIncludeFile(char * Pathname)1199 PrDoIncludeFile (
1200 char *Pathname)
1201 {
1202 char *FullPathname;
1203
1204
1205 (void) PrOpenIncludeFile (Pathname, "r", &FullPathname);
1206 }
1207
1208
1209 /*******************************************************************************
1210 *
1211 * FUNCTION: PrDoIncludeBuffer
1212 *
1213 * PARAMETERS: Pathname - Name of the input binary file
1214 * BufferName - ACPI namepath of the buffer
1215 *
1216 * RETURN: None.
1217 *
1218 * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents
1219 * of the file are emitted into the buffer object as ascii
1220 * hex data. From #includebuffer.
1221 *
1222 ******************************************************************************/
1223
1224 static void
PrDoIncludeBuffer(char * Pathname,char * BufferName)1225 PrDoIncludeBuffer (
1226 char *Pathname,
1227 char *BufferName)
1228 {
1229 char *FullPathname;
1230 FILE *BinaryBufferFile;
1231 UINT32 i = 0;
1232 UINT8 c;
1233
1234
1235 BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname);
1236 if (!BinaryBufferFile)
1237 {
1238 return;
1239 }
1240
1241 /* Emit "Name (XXXX, Buffer() {" header */
1242
1243 FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName);
1244
1245 /* Dump the entire file in ascii hex format */
1246
1247 while (fread (&c, 1, 1, BinaryBufferFile))
1248 {
1249 if (!(i % 8))
1250 {
1251 FlPrintFile (ASL_FILE_PREPROCESSOR, "\n ");
1252 }
1253
1254 FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c);
1255 i++;
1256 }
1257
1258 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
1259 "#includebuffer: read %u bytes from %s\n",
1260 AslGbl_CurrentLineNumber, i, FullPathname);
1261
1262 /* Close the Name() operator */
1263
1264 FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n");
1265 fclose (BinaryBufferFile);
1266 }
1267