glsl: glcpp: Move handling of #line directives from lexer to parser.
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>
This commit is contained in:
@@ -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>{
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user