xref: /freebsd/sys/contrib/dev/acpica/compiler/aslsupport.l (revision 6486b015fc84e96725fef22b0e3363351399ae83)
1 
2 /******************************************************************************
3  *
4  * Module Name: aslsupport.l - Flex/lex scanner C support routines.
5  *              NOTE: Included into aslcompile.l, not compiled by itself.
6  *
7  *****************************************************************************/
8 
9 /*
10  * Copyright (C) 2000 - 2012, Intel Corp.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions, and the following disclaimer,
18  *    without modification.
19  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
20  *    substantially similar to the "NO WARRANTY" disclaimer below
21  *    ("Disclaimer") and any redistribution must be conditioned upon
22  *    including a substantially similar Disclaimer requirement for further
23  *    binary redistribution.
24  * 3. Neither the names of the above-listed copyright holders nor the names
25  *    of any contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * Alternatively, this software may be distributed under the terms of the
29  * GNU General Public License ("GPL") version 2 as published by the Free
30  * Software Foundation.
31  *
32  * NO WARRANTY
33  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
36  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
42  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43  * POSSIBILITY OF SUCH DAMAGES.
44  */
45 
46 
47 /* Configuration */
48 
49 #define ASL_SPACES_PER_TAB      4
50 
51 #define ASL_NORMAL_CHAR         0
52 #define ASL_ESCAPE_SEQUENCE     1
53 #define ASL_OCTAL_CONSTANT      2
54 #define ASL_HEX_CONSTANT        3
55 
56 
57 /* File node - used for "Include" operator file stack */
58 
59 typedef struct asl_file_node
60 {
61     FILE                    *File;
62     UINT32                  CurrentLineNumber;
63     YY_BUFFER_STATE         State;
64     char                    *Filename;
65     struct asl_file_node    *Next;
66 
67 } ASL_FILE_NODE;
68 
69 /* File stack for the "Include" operator (NOT #include operator) */
70 
71 ASL_FILE_NODE               *Gbl_IncludeFileStack = NULL;
72 
73 
74 /*******************************************************************************
75  *
76  * FUNCTION:    AslDoLineDirective
77  *
78  * PARAMETERS:  None. Uses input() to access current source code line
79  *
80  * RETURN:      Updates global line number and filename
81  *
82  * DESCRIPTION: Handle #line directives emitted by the preprocessor.
83  *
84  * The #line directive is emitted by the preprocesser, and is used to
85  * pass through line numbers from the original source code file to the
86  * preprocessor output file (.i). This allows any compiler-generated
87  * error messages to be displayed with the correct line number.
88  *
89  ******************************************************************************/
90 
91 static void
92 AslDoLineDirective (
93     void)
94 {
95     char                    c;
96     char                    *Token;
97     UINT32                  LineNumber;
98     char                    *Filename;
99 
100 
101     /* Eat the entire line that contains the #line directive */
102 
103     while ((c = (char) input()) != '\n' && c != EOF)
104     {
105         AslInsertLineBuffer (c);
106     }
107     AslInsertLineBuffer (0);
108 
109     /* First argument is the actual line number */
110 
111     Token = strtok (Gbl_CurrentLineBuffer, " ");
112     if (!Token)
113     {
114         goto ResetAndExit;
115     }
116 
117     /* Convert line number. Subtract one to handle _this_ line */
118 
119     LineNumber = (UINT32) UtDoConstant (Token);
120     FlSetLineNumber (LineNumber - 1);
121 
122     /* Second argument is the optional filename (in double quotes) */
123 
124     Token = strtok (NULL, " \"");
125     if (Token)
126     {
127         Filename = ACPI_ALLOCATE_ZEROED (strlen (Token) + 1);
128         strcpy (Filename, Token);
129         FlSetFilename (Filename);
130     }
131 
132     /* Third argument is not supported at this time */
133 
134 ResetAndExit:
135     AslResetCurrentLineBuffer ();
136 }
137 
138 
139 /*******************************************************************************
140  *
141  * FUNCTION:    AslPopInputFileStack
142  *
143  * PARAMETERS:  None
144  *
145  * RETURN:      0 if a node was popped, -1 otherwise
146  *
147  * DESCRIPTION: Pop the top of the input file stack and point the parser to
148  *              the saved parse buffer contained in the fnode.  Also, set the
149  *              global line counters to the saved values.  This function is
150  *              called when an include file reaches EOF.
151  *
152  ******************************************************************************/
153 
154 int
155 AslPopInputFileStack (
156     void)
157 {
158     ASL_FILE_NODE           *Fnode;
159 
160 
161     Fnode = Gbl_IncludeFileStack;
162     DbgPrint (ASL_PARSE_OUTPUT, "\nPop InputFile Stack, Fnode %p\n\n", Fnode);
163 
164     if (!Fnode)
165     {
166         return (-1);
167     }
168 
169     /* Close the current include file */
170 
171     fclose (yyin);
172 
173     /* Update the top-of-stack */
174 
175     Gbl_IncludeFileStack = Fnode->Next;
176 
177     /* Reset global line counter and filename */
178 
179     Gbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename;
180     Gbl_CurrentLineNumber = Fnode->CurrentLineNumber;
181 
182     /* Point the parser to the popped file */
183 
184     yy_delete_buffer (YY_CURRENT_BUFFER);
185     yy_switch_to_buffer (Fnode->State);
186 
187     /* All done with this node */
188 
189     ACPI_FREE (Fnode);
190     return (0);
191 }
192 
193 
194 /*******************************************************************************
195  *
196  * FUNCTION:    AslPushInputFileStack
197  *
198  * PARAMETERS:  InputFile           - Open file pointer
199  *              Filename            - Name of the file
200  *
201  * RETURN:      None
202  *
203  * DESCRIPTION: Push the InputFile onto the file stack, and point the parser
204  *              to this file.  Called when an include file is successfully
205  *              opened.
206  *
207  ******************************************************************************/
208 
209 void
210 AslPushInputFileStack (
211     FILE                    *InputFile,
212     char                    *Filename)
213 {
214     ASL_FILE_NODE           *Fnode;
215     YY_BUFFER_STATE         State;
216 
217 
218     /* Save the current state in an Fnode */
219 
220     Fnode = UtLocalCalloc (sizeof (ASL_FILE_NODE));
221 
222     Fnode->File                 = yyin;
223     Fnode->Next                 = Gbl_IncludeFileStack;
224     Fnode->State                = YY_CURRENT_BUFFER;
225     Fnode->CurrentLineNumber    = Gbl_CurrentLineNumber;
226     Fnode->Filename             = Gbl_Files[ASL_FILE_INPUT].Filename;
227 
228     /* Push it on the stack */
229 
230     Gbl_IncludeFileStack = Fnode;
231 
232     /* Point the parser to this file */
233 
234     State = yy_create_buffer (InputFile, YY_BUF_SIZE);
235     yy_switch_to_buffer (State);
236 
237     DbgPrint (ASL_PARSE_OUTPUT, "\nPush InputFile Stack, returning %p\n\n", InputFile);
238 
239     /* Reset the global line count and filename */
240 
241     Gbl_Files[ASL_FILE_INPUT].Filename = Filename;
242     Gbl_CurrentLineNumber = 1;
243     yyin = InputFile;
244 }
245 
246 
247 /*******************************************************************************
248  *
249  * FUNCTION:    AslResetCurrentLineBuffer
250  *
251  * PARAMETERS:  None
252  *
253  * RETURN:      None
254  *
255  * DESCRIPTION: Reset the Line Buffer to zero, increment global line numbers.
256  *
257  ******************************************************************************/
258 
259 void
260 AslResetCurrentLineBuffer (
261     void)
262 {
263 
264     if (Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Handle)
265     {
266         FlWriteFile (ASL_FILE_SOURCE_OUTPUT, Gbl_CurrentLineBuffer,
267             Gbl_LineBufPtr - Gbl_CurrentLineBuffer);
268     }
269 
270     Gbl_CurrentLineOffset += Gbl_CurrentColumn;
271     Gbl_CurrentColumn = 0;
272 
273     Gbl_CurrentLineNumber++;
274     Gbl_LogicalLineNumber++;
275     Gbl_LineBufPtr = Gbl_CurrentLineBuffer;
276 }
277 
278 
279 /*******************************************************************************
280  *
281  * FUNCTION:    AslInsertLineBuffer
282  *
283  * PARAMETERS:  SourceChar      - One char from the input ASL source file
284  *
285  * RETURN:      None
286  *
287  * DESCRIPTION: Put one character of the source file into the temp line buffer
288  *
289  ******************************************************************************/
290 
291 void
292 AslInsertLineBuffer (
293     int                     SourceChar)
294 {
295     UINT32                  i;
296     UINT32                  Count = 1;
297 
298 
299     if (SourceChar == EOF)
300     {
301         return;
302     }
303 
304     Gbl_InputByteCount++;
305 
306     /* Handle tabs.  Convert to spaces */
307 
308     if (SourceChar == '\t')
309     {
310         SourceChar = ' ';
311         Count = ASL_SPACES_PER_TAB -
312                     (Gbl_CurrentColumn & (ASL_SPACES_PER_TAB-1));
313     }
314 
315     for (i = 0; i < Count; i++)
316     {
317         Gbl_CurrentColumn++;
318 
319         /* Insert the character into the line buffer */
320 
321         *Gbl_LineBufPtr = (UINT8) SourceChar;
322         Gbl_LineBufPtr++;
323 
324         if (Gbl_LineBufPtr > (Gbl_CurrentLineBuffer + (ASL_LINE_BUFFER_SIZE - 1)))
325         {
326 #if 0
327             /*
328              * Warning if we have split a long source line.
329              * <Probably overkill>
330              */
331             sprintf (MsgBuffer, "Max %u", ASL_LINE_BUFFER_SIZE);
332             AslCommonError (ASL_WARNING, ASL_MSG_LONG_LINE,
333                             Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
334                             Gbl_CurrentLineOffset, Gbl_CurrentColumn,
335                             Gbl_Files[ASL_FILE_INPUT].Filename, MsgBuffer);
336 #endif
337 
338             AslResetCurrentLineBuffer ();
339         }
340         else if (SourceChar == '\n')
341         {
342             /* End of line */
343 
344             AslResetCurrentLineBuffer ();
345         }
346     }
347 }
348 
349 
350 /*******************************************************************************
351  *
352  * FUNCTION:    count
353  *
354  * PARAMETERS:  yytext      - Contains the matched keyword.
355  *              Type        - Keyword/Character type:
356  *                             0 = anything except a keyword
357  *                             1 = pseudo-keywords
358  *                             2 = non-executable ASL keywords
359  *                             3 = executable ASL keywords
360  *
361  * RETURN:      None
362  *
363  * DESCRIPTION: Count keywords and put them into the line buffer
364  *
365  ******************************************************************************/
366 
367 static void
368 count (
369     int                 Type)
370 {
371     int                 i;
372 
373 
374     switch (Type)
375     {
376     case 2:
377         TotalKeywords++;
378         TotalNamedObjects++;
379         break;
380 
381     case 3:
382         TotalKeywords++;
383         TotalExecutableOpcodes++;
384         break;
385     }
386 
387     for (i = 0; (yytext[i] != 0) && (yytext[i] != EOF); i++)
388     {
389         AslInsertLineBuffer (yytext[i]);
390         *Gbl_LineBufPtr = 0;
391     }
392 }
393 
394 
395 /*******************************************************************************
396  *
397  * FUNCTION:    AslDoComment
398  *
399  * PARAMETERS:  none
400  *
401  * RETURN:      none
402  *
403  * DESCRIPTION: Process a standard comment.
404  *
405  ******************************************************************************/
406 
407 static char
408 AslDoComment (
409     void)
410 {
411     char                c;
412     char                c1 = 0;
413 
414 
415     AslInsertLineBuffer ('/');
416     AslInsertLineBuffer ('*');
417 
418 loop:
419 
420     /* Eat chars until end-of-comment */
421 
422     while ((c = (char) input()) != '*' && c != EOF)
423     {
424         AslInsertLineBuffer (c);
425         c1 = c;
426     }
427 
428     if (c == EOF)
429     {
430         goto EarlyEOF;
431     }
432 
433     /*
434      * Check for nested comment -- can help catch cases where a previous
435      * comment was accidently left unterminated
436      */
437     if ((c1 == '/') && (c == '*'))
438     {
439         AslCommonError (ASL_WARNING, ASL_MSG_NESTED_COMMENT,
440                         Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
441                         Gbl_InputByteCount, Gbl_CurrentColumn,
442                         Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
443     }
444 
445     /* Comment is closed only if the NEXT character is a slash */
446 
447     AslInsertLineBuffer (c);
448 
449     if ((c1 = (char) input()) != '/' && c1 != EOF)
450     {
451         unput(c1);
452         goto loop;
453     }
454 
455     if (c1 == EOF)
456     {
457         goto EarlyEOF;
458     }
459 
460     AslInsertLineBuffer (c1);
461     return (TRUE);
462 
463 
464 EarlyEOF:
465     /*
466      * Premature End-Of-File
467      */
468     AslCommonError (ASL_ERROR, ASL_MSG_EARLY_EOF,
469                     Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
470                     Gbl_CurrentLineOffset, Gbl_CurrentColumn,
471                     Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
472     return (FALSE);
473 }
474 
475 
476 /*******************************************************************************
477  *
478  * FUNCTION:    AslDoCommentType2
479  *
480  * PARAMETERS:  none
481  *
482  * RETURN:      none
483  *
484  * DESCRIPTION: Process a new "//" comment.
485  *
486  ******************************************************************************/
487 
488 static char
489 AslDoCommentType2 (
490     void)
491 {
492     char                c;
493 
494 
495     AslInsertLineBuffer ('/');
496     AslInsertLineBuffer ('/');
497 
498     while ((c = (char) input()) != '\n' && c != EOF)
499     {
500         AslInsertLineBuffer (c);
501     }
502 
503     if (c == EOF)
504     {
505         /* End of file is OK, change to newline. Let parser detect EOF later */
506 
507         c = '\n';
508     }
509 
510     AslInsertLineBuffer (c);
511     return (TRUE);
512 }
513 
514 
515 /*******************************************************************************
516  *
517  * FUNCTION:    AslDoStringLiteral
518  *
519  * PARAMETERS:  none
520  *
521  * RETURN:      none
522  *
523  * DESCRIPTION: Process a string literal (surrounded by quotes)
524  *
525  ******************************************************************************/
526 
527 static char
528 AslDoStringLiteral (
529     void)
530 {
531     char                *StringBuffer = MsgBuffer;
532     char                *EndBuffer = MsgBuffer + ASL_MSG_BUFFER_SIZE;
533     char                *CleanString;
534     char                StringChar;
535     UINT32              State = ASL_NORMAL_CHAR;
536     UINT32              i = 0;
537     UINT8               Digit;
538     char                ConvertBuffer[4];
539 
540 
541     /*
542      * Eat chars until end-of-literal.
543      * NOTE:  Put back the original surrounding quotes into the
544      * source line buffer.
545      */
546     AslInsertLineBuffer ('\"');
547     while ((StringChar = (char) input()) != EOF)
548     {
549         AslInsertLineBuffer (StringChar);
550 
551 DoCharacter:
552 
553         switch (State)
554         {
555         case ASL_NORMAL_CHAR:
556 
557             switch (StringChar)
558             {
559             case '\\':
560                 /*
561                  * Special handling for backslash-escape sequence.  We will
562                  * toss the backslash and translate the escape char(s).
563                  */
564                 State = ASL_ESCAPE_SEQUENCE;
565                 continue;
566 
567             case '\"':
568 
569                 /* String terminator */
570 
571                 goto CompletedString;
572             }
573             break;
574 
575 
576         case ASL_ESCAPE_SEQUENCE:
577 
578             State = ASL_NORMAL_CHAR;
579             switch (StringChar)
580             {
581             case 'a':
582                 StringChar = 0x07;      /* BELL */
583                 break;
584 
585             case 'b':
586                 StringChar = 0x08;      /* BACKSPACE */
587                 break;
588 
589             case 'f':
590                 StringChar = 0x0C;      /* FORMFEED */
591                 break;
592 
593             case 'n':
594                 StringChar = 0x0A;      /* LINEFEED */
595                 break;
596 
597             case 'r':
598                 StringChar = 0x0D;      /* CARRIAGE RETURN*/
599                 break;
600 
601             case 't':
602                 StringChar = 0x09;      /* HORIZONTAL TAB */
603                 break;
604 
605             case 'v':
606                 StringChar = 0x0B;      /* VERTICAL TAB */
607                 break;
608 
609             case 'x':
610                 State = ASL_HEX_CONSTANT;
611                 i = 0;
612                 continue;
613 
614             case '\'':                  /* Single Quote */
615             case '\"':                  /* Double Quote */
616             case '\\':                  /* Backslash */
617                 break;
618 
619             default:
620 
621                 /* Check for an octal digit (0-7) */
622 
623                 if (ACPI_IS_OCTAL_DIGIT (StringChar))
624                 {
625                     State = ASL_OCTAL_CONSTANT;
626                     ConvertBuffer[0] = StringChar;
627                     i = 1;
628                     continue;
629                 }
630 
631                 /* Unknown escape sequence issue warning, but use the character */
632 
633                 AslCommonError (ASL_WARNING, ASL_MSG_INVALID_ESCAPE,
634                                 Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
635                                 Gbl_CurrentLineOffset, Gbl_CurrentColumn,
636                                 Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
637                 break;
638             }
639             break;
640 
641 
642         case ASL_OCTAL_CONSTANT:
643 
644             /* Up to three octal digits allowed */
645 
646             if (!ACPI_IS_OCTAL_DIGIT (StringChar) ||
647                 (i > 2))
648             {
649                 /*
650                  * Reached end of the constant.  Convert the assembled ASCII
651                  * string and resume processing of the next character
652                  */
653                 ConvertBuffer[i] = 0;
654                 Digit = (UINT8) ACPI_STRTOUL (ConvertBuffer, NULL, 8);
655 
656                 /* Check for NULL or non-ascii character (ignore if so) */
657 
658                 if ((Digit == 0) || (Digit > ACPI_ASCII_MAX))
659                 {
660                     AslCommonError (ASL_WARNING, ASL_MSG_INVALID_STRING,
661                                     Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
662                                     Gbl_CurrentLineOffset, Gbl_CurrentColumn,
663                                     Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
664                 }
665                 else
666                 {
667                     *StringBuffer = (char) Digit;
668                     StringBuffer++;
669                     if (StringBuffer >= EndBuffer)
670                     {
671                         goto BufferOverflow;
672                     }
673                 }
674 
675                 State = ASL_NORMAL_CHAR;
676                 goto DoCharacter;
677                 break;
678             }
679 
680             /* Append another digit of the constant */
681 
682             ConvertBuffer[i] = StringChar;
683             i++;
684             continue;
685 
686 
687         case ASL_HEX_CONSTANT:
688 
689             /* Up to two hex digits allowed */
690 
691             if (!ACPI_IS_XDIGIT (StringChar) ||
692                 (i > 1))
693             {
694                 /*
695                  * Reached end of the constant.  Convert the assembled ASCII
696                  * string and resume processing of the next character
697                  */
698                 ConvertBuffer[i] = 0;
699                 Digit = (UINT8) ACPI_STRTOUL (ConvertBuffer, NULL, 16);
700 
701                 /* Check for NULL or non-ascii character (ignore if so) */
702 
703                 if ((Digit == 0) || (Digit > ACPI_ASCII_MAX))
704                 {
705                     AslCommonError (ASL_WARNING, ASL_MSG_INVALID_STRING,
706                                     Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
707                                     Gbl_CurrentLineOffset, Gbl_CurrentColumn,
708                                     Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
709                 }
710                 else
711                 {
712                     *StringBuffer = (char) Digit;
713                     StringBuffer++;
714                     if (StringBuffer >= EndBuffer)
715                     {
716                         goto BufferOverflow;
717                     }
718                 }
719 
720                 State = ASL_NORMAL_CHAR;
721                 goto DoCharacter;
722                 break;
723             }
724 
725             /* Append another digit of the constant */
726 
727             ConvertBuffer[i] = StringChar;
728             i++;
729             continue;
730         }
731 
732         /* Save the finished character */
733 
734         *StringBuffer = StringChar;
735         StringBuffer++;
736         if (StringBuffer >= EndBuffer)
737         {
738             goto BufferOverflow;
739         }
740     }
741 
742     /*
743      * Premature End-Of-File
744      */
745     AslCommonError (ASL_ERROR, ASL_MSG_EARLY_EOF,
746                     Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
747                     Gbl_CurrentLineOffset, Gbl_CurrentColumn,
748                     Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
749     return (FALSE);
750 
751 
752 CompletedString:
753     /*
754      * Null terminate the input string and copy string to a new buffer
755      */
756     *StringBuffer = 0;
757 
758     CleanString = UtGetStringBuffer (strlen (MsgBuffer) + 1);
759     if (!CleanString)
760     {
761         AslCommonError (ASL_ERROR, ASL_MSG_MEMORY_ALLOCATION,
762                         Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
763                         Gbl_CurrentLineOffset, Gbl_CurrentColumn,
764                         Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
765         return (FALSE);
766     }
767 
768     ACPI_STRCPY (CleanString, MsgBuffer);
769     AslCompilerlval.s = CleanString;
770     return (TRUE);
771 
772 
773 BufferOverflow:
774 
775     /* Literal was too long */
776 
777     AslCommonError (ASL_ERROR, ASL_MSG_STRING_LENGTH,
778                     Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
779                     Gbl_CurrentLineOffset, Gbl_CurrentColumn,
780                     Gbl_Files[ASL_FILE_INPUT].Filename, "Max length 4096");
781     return (FALSE);
782 }
783