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