glsl: glcpp: Move handling of #line directives from lexer to parser.
authorCarl Worth <cworth@cworth.org>
Sat, 9 Jun 2012 23:31:06 +0000 (16:31 -0700)
committerCarl Worth <cworth@cworth.org>
Tue, 26 Jun 2012 22:23:49 +0000 (15:23 -0700)
The GLSL specification requires that #line directives be interpreted
after macro expansion. Our existing implementation of #line macros in
the lexer prevents conformance on this point.

Moving the handling of #line from the lexer to the parser gives us the
macro expansion we need. An additional benefit is that the
preprocessor also now supports comments on the same line as #line
directives.

Finally, the preprocessor now emits the (fully-macro-expanded) #line
directives into the output. This allows the full GLSL compiler to also
see and interpret these directives so it can also generate correct
line numbers in error messages.

Signed-off-by: Carl Worth <cworth@cworth.org>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/glsl/glcpp/glcpp-lex.l
src/glsl/glcpp/glcpp-parse.y
src/glsl/glcpp/glcpp.h
src/glsl/glcpp/tests/091-hash-line.c.expected

index b34f2c0..7ab58cb 100644 (file)
@@ -40,12 +40,18 @@ void glcpp_set_column (int  column_no , yyscan_t yyscanner);
 
 #define YY_NO_INPUT
 
-#define YY_USER_ACTION                                          \
-   do {                                                         \
-      yylloc->first_column = yycolumn + 1;                      \
-      yylloc->first_line = yylineno;                            \
-      yycolumn += yyleng;                                       \
-   } while(0);
+#define YY_USER_ACTION                                                 \
+       do {                                                            \
+               if (parser->has_new_line_number)                        \
+                       yylineno = parser->new_line_number;             \
+               if (parser->has_new_source_number)                      \
+                       yylloc->source = parser->new_source_number;     \
+               yylloc->first_column = yycolumn + 1;                    \
+               yylloc->first_line = yylineno;                          \
+               yycolumn += yyleng;                                     \
+               parser->has_new_line_number = 0;                        \
+               parser->has_new_source_number = 0;                      \
+ } while(0);
 
 #define YY_USER_INIT                   \
        do {                            \
@@ -129,35 +135,8 @@ HEXADECIMAL_INTEGER        0[xX][0-9a-fA-F]+[uU]?
        return OTHER;
 }
 
-{HASH}line{HSPACE}+{DIGITS}{HSPACE}+{DIGITS}{HSPACE}*$ {
-       /* Eat characters until the first digit is
-        * encountered
-        */
-       char *ptr = yytext;
-       while (!isdigit(*ptr))
-               ptr++;
-
-       /* Subtract one from the line number because
-        * yylineno is zero-based instead of
-        * one-based.
-        */
-       yylineno = strtol(ptr, &ptr, 0) - 1;
-       yylloc->source = strtol(ptr, NULL, 0);
-}
-
-{HASH}line{HSPACE}+{DIGITS}{HSPACE}*$ {
-       /* Eat characters until the first digit is
-        * encountered
-        */
-       char *ptr = yytext;
-       while (!isdigit(*ptr))
-               ptr++;
-
-       /* Subtract one from the line number because
-        * yylineno is zero-based instead of
-        * one-based.
-        */
-       yylineno = strtol(ptr, &ptr, 0) - 1;
+{HASH}line {
+       return HASH_LINE;
 }
 
 <SKIP,INITIAL>{
index ee00180..cc4af16 100644 (file)
@@ -162,7 +162,7 @@ add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
 %lex-param {glcpp_parser_t *parser}
 
 %expect 0
-%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE
+%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_LINE HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE
 %token PASTE
 %type <ival> expression INTEGER operator SPACE integer_constant
 %type <str> IDENTIFIER INTEGER_STRING OTHER
@@ -208,6 +208,24 @@ expanded_line:
 |      ELIF_EXPANDED expression NEWLINE {
                _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2);
        }
+|      LINE_EXPANDED integer_constant NEWLINE {
+               parser->has_new_line_number = 1;
+               parser->new_line_number = $2;
+               ralloc_asprintf_rewrite_tail (&parser->output,
+                                             &parser->output_length,
+                                             "#line %" PRIiMAX,
+                                             $2);
+       }
+|      LINE_EXPANDED integer_constant integer_constant NEWLINE {
+               parser->has_new_line_number = 1;
+               parser->new_line_number = $2;
+               parser->has_new_source_number = 1;
+               parser->new_source_number = $3;
+               ralloc_asprintf_rewrite_tail (&parser->output,
+                                             &parser->output_length,
+                                             "#line %" PRIiMAX " %" PRIiMAX,
+                                             $2, $3);
+       }
 ;
 
 control_line:
@@ -228,6 +246,14 @@ control_line:
                }
                ralloc_free ($2);
        }
+|      HASH_LINE pp_tokens NEWLINE {
+               if (parser->skip_stack == NULL ||
+                   parser->skip_stack->type == SKIP_NO_SKIP)
+               {
+                       _glcpp_parser_expand_and_lex_from (parser,
+                                                          LINE_EXPANDED, $2);
+               }
+       }
 |      HASH_IF conditional_tokens NEWLINE {
                /* Be careful to only evaluate the 'if' expression if
                 * we are not skipping. When we are skipping, we
@@ -1120,6 +1146,11 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
        parser->info_log_length = 0;
        parser->error = 0;
 
+       parser->has_new_line_number = 0;
+       parser->new_line_number = 1;
+       parser->has_new_source_number = 0;
+       parser->new_source_number = 0;
+
        /* Add pre-defined macros. */
        add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
        add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
index 2d7cad2..a13ade6 100644 (file)
@@ -25,6 +25,7 @@
 #define GLCPP_H
 
 #include <stdint.h>
+#include <stdbool.h>
 
 #include "../ralloc.h"
 
@@ -177,6 +178,10 @@ struct glcpp_parser {
        size_t output_length;
        size_t info_log_length;
        int error;
+       bool has_new_line_number;
+       int new_line_number;
+       bool has_new_source_number;
+       int new_source_number;
 };
 
 struct gl_extensions;
index e663398..ea29149 100644 (file)
@@ -3,11 +3,11 @@
 1:0(1): preprocessor error: #error source 1, line 0 error
 2:30(1): preprocessor error: #error source 2, line 30 error
 
+#line 0
 
+#line 25
 
+#line 0 1
 
-
-
-
-
+#line 30 2