[Mesa-dev] [PATCH] glcpp: Add support to #line for a filnename, not just a source string number

Carl Worth cworth at cworth.org
Fri Nov 30 10:36:37 PST 2012


Such as:

	#line 23 "foo.c"

Having a filename here is quite useful and many other OpenGL implementations
allow this.

Note that for GLES we take the hard line and insist on a numeric source string
number as per the specification and which glcpp has always supported:

	#line 23 3
---

This is something of a proof-of-concept for now.

Ian mentioned to me yesterday that he would like to have support for '#line XX
"filename.c"' has described above. And this is my quickest implementation of
that.

This is simple in that the string literal is not actually interpreted, (escape
sequences aren't converted into their representations). The escape sequences
are properly captured by a regular expression, but all just sucked up
literally. This was easier to write, and is also what we want for re-emitting
the #line directive, (with all of the escape sequences in place).

This is slightly bogus for emitting the error messages, though. You'll get a
C-formatted string literal instead of a filename. At a minimum this will look
like:

	"foo.c":25: Syntax error

So there are extra quotation marks there. And it will appear uglier if there
are further escape sequences in the string. Fixing this would mean writing a
fair amount of code to decode the C string literal, and then additional code
to re-encode it to emit the #line directive.

It's not totally clear to me whether that's all worth it. (Note that the code
does exist in many implementations of C grammars, so it would be easy to find
a version that we could legitimately copy into our implementation.)

Meanwhile, the bigger issue that makes this just a proof-of-concept is that
only the pre-processor is changed here. And unlike something like #define, the
downstream compiler still sees #line directives emitted by the
pre-processor. So a complete implementation of the feature of interest here
requires augmenting the downstream code that is handling #line.

I'll look at that next, but just wanted to mention the issue of string
interpretation here first.

And yes, it is silly that we are parsing #line in two different places of the
code. Someday we'll have to integrate the GLSL compiler's parser with the
output of the preprocessor, (drop the GLSL compiler's separate lexer, and make
the preprocessor emit tokens rather than strings). When we do that, a feature
like this one will be simpler.

-Carl

 src/glsl/glcpp/glcpp-lex.l   |   15 ++++++++++-----
 src/glsl/glcpp/glcpp-parse.y |   34 ++++++++++++++++++++++++++--------
 src/glsl/glcpp/glcpp.h       |    8 ++++----
 src/glsl/glcpp/pp.c          |    4 ++--
 4 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/src/glsl/glcpp/glcpp-lex.l b/src/glsl/glcpp/glcpp-lex.l
index 783c545..893ce66 100644
--- a/src/glsl/glcpp/glcpp-lex.l
+++ b/src/glsl/glcpp/glcpp-lex.l
@@ -44,20 +44,20 @@ void glcpp_set_column (int  column_no , yyscan_t yyscanner);
 	do {								\
 		if (parser->has_new_line_number)			\
 			yylineno = parser->new_line_number;		\
-		if (parser->has_new_source_number)			\
-			yylloc->source = parser->new_source_number;	\
+		if (parser->has_new_source)				\
+			yylloc->source = parser->new_source;		\
 		yylloc->first_column = yycolumn + 1;			\
 		yylloc->first_line = yylineno;				\
 		yycolumn += yyleng;					\
 		parser->has_new_line_number = 0;			\
-		parser->has_new_source_number = 0;			\
+		parser->has_new_source = 0;				\
  } while(0);
 
 #define YY_USER_INIT			\
 	do {				\
 		yylineno = 1;		\
 		yycolumn = 1;		\
-		yylloc->source = 0;	\
+		yylloc->source = "0";	\
 	} while(0)
 %}
 
@@ -84,7 +84,7 @@ strings, we have to be careful to avoid OTHER matching and hiding
 something that CPP does care about. So we simply exclude all
 characters that appear in any other expressions. */
 
-OTHER		[^][_#[:space:]#a-zA-Z0-9(){}.&*~!/%<>^|;,=+-]
+OTHER		[^][_#[:space:]#a-zA-Z0-9(){}.&*~!/%<>^|;,="+-]
 
 DIGITS			[0-9][0-9]*
 DECIMAL_INTEGER		[1-9][0-9]*[uU]?
@@ -120,6 +120,11 @@ HEXADECIMAL_INTEGER	0[xX][0-9a-fA-F]+[uU]?
 		return SPACE;
 }
 
+\"(\\.|[^\\"\n])*\" {
+	yylval->str = ralloc_strdup (yyextra, yytext);
+	return STRING_LITERAL;
+}
+
 {HASH}version {
 	yylval->str = ralloc_strdup (yyextra, yytext);
 	yyextra->space_tokens = 0;
diff --git a/src/glsl/glcpp/glcpp-parse.y b/src/glsl/glcpp/glcpp-parse.y
index bdf7e17..7d7499d 100644
--- a/src/glsl/glcpp/glcpp-parse.y
+++ b/src/glsl/glcpp/glcpp-parse.y
@@ -164,10 +164,10 @@ 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_IDENTIFIER OBJ_IDENTIFIER 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 COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE FUNC_IDENTIFIER OBJ_IDENTIFIER 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 STRING_LITERAL
 %token PASTE
 %type <ival> expression INTEGER operator SPACE integer_constant
-%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER
+%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER STRING_LITERAL
 %type <string_list> identifier_list
 %type <token> preprocessing_token conditional_token
 %type <token_list> pp_tokens replacement_list text_line conditional_tokens
@@ -229,13 +229,25 @@ expanded_line:
 |	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;
+		parser->has_new_source = 1;
+		parser->new_source = ralloc_asprintf (parser, "%" PRIiMAX, $3);
 		ralloc_asprintf_rewrite_tail (&parser->output,
 					      &parser->output_length,
 					      "#line %" PRIiMAX " %" PRIiMAX "\n",
 					      $2, $3);
 	}
+|	LINE_EXPANDED integer_constant STRING_LITERAL NEWLINE {
+		if (parser->is_gles)
+			glcpp_error(& @1, parser, "#line with non-numeric source number (illegal in GLES)");
+		parser->has_new_line_number = 1;
+		parser->new_line_number = $2;
+		parser->has_new_source = 1;
+		parser->new_source = $3;
+		ralloc_asprintf_rewrite_tail (&parser->output,
+					      &parser->output_length,
+					      "#line %" PRIiMAX " %s\n",
+					      $2, $3);
+	}
 ;
 
 control_line:
@@ -542,6 +554,10 @@ preprocessing_token:
 		$$ = _token_create_ival (parser, SPACE, SPACE);
 		$$->location = yylloc;
 	}
+|	STRING_LITERAL {
+   		$$ = _token_create_str (parser, STRING_LITERAL, $1);
+		$$->location = yylloc;
+	}
 ;
 
 operator:
@@ -913,6 +929,7 @@ _token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
 		case IDENTIFIER:
 		case INTEGER_STRING:
 		case OTHER:
+		case STRING_LITERAL:
 			if (strcmp (node_a->token->value.str,
 				    node_b->token->value.str))
 			{
@@ -943,6 +960,7 @@ _token_print (char **out, size_t *len, token_t *token)
 	case IDENTIFIER:
 	case INTEGER_STRING:
 	case OTHER:
+	case STRING_LITERAL:
 		ralloc_asprintf_rewrite_tail (out, len, "%s", token->value.str);
 		break;
 	case SPACE:
@@ -1053,8 +1071,8 @@ _token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
 	 * valid, single pre-processing token. For example, pasting
 	 * "123" and "abc" is not legal, but we don't catch that
 	 * here. */
-	if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
-	    (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
+	if ((token->type == IDENTIFIER || token->type == OTHER || token->type == STRING_LITERAL || token->type == INTEGER_STRING) &&
+	    (other->type == IDENTIFIER || other->type == OTHER || other->type == STRING_LITERAL || other->type == INTEGER_STRING))
 	{
 		char *str;
 
@@ -1137,8 +1155,8 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
 
 	parser->has_new_line_number = 0;
 	parser->new_line_number = 1;
-	parser->has_new_source_number = 0;
-	parser->new_source_number = 0;
+	parser->has_new_source = 0;
+	parser->new_source = "0";
 
 	parser->is_gles = false;
 
diff --git a/src/glsl/glcpp/glcpp.h b/src/glsl/glcpp/glcpp.h
index 03a77b7..b564177 100644
--- a/src/glsl/glcpp/glcpp.h
+++ b/src/glsl/glcpp/glcpp.h
@@ -65,7 +65,7 @@ typedef struct YYLTYPE {
    int first_column;
    int last_line;
    int last_column;
-   unsigned source;
+   const char *source;
 } YYLTYPE;
 # define YYLTYPE_IS_DECLARED 1
 # define YYLTYPE_IS_TRIVIAL 1
@@ -86,7 +86,7 @@ do {								\
       (Current).first_column = (Current).last_column =		\
 	 YYRHSLOC(Rhs, 0).last_column;				\
    }								\
-   (Current).source = 0;					\
+   (Current).source = "0";					\
 } while (0)
 
 struct token {
@@ -180,8 +180,8 @@ struct glcpp_parser {
 	int error;
 	bool has_new_line_number;
 	int new_line_number;
-	bool has_new_source_number;
-	int new_source_number;
+	bool has_new_source;
+	const char *new_source;
 	bool is_gles;
 };
 
diff --git a/src/glsl/glcpp/pp.c b/src/glsl/glcpp/pp.c
index 11b2941..6062150 100644
--- a/src/glsl/glcpp/pp.c
+++ b/src/glsl/glcpp/pp.c
@@ -35,7 +35,7 @@ glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
 	parser->error = 1;
 	ralloc_asprintf_rewrite_tail(&parser->info_log,
 				     &parser->info_log_length,
-				     "%u:%u(%u): "
+				     "%s:%u(%u): "
 				     "preprocessor error: ",
 				     locp->source,
 				     locp->first_line,
@@ -56,7 +56,7 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
 
 	ralloc_asprintf_rewrite_tail(&parser->info_log,
 				     &parser->info_log_length,
-				     "%u:%u(%u): "
+				     "%s:%u(%u): "
 				     "preprocessor warning: ",
 				     locp->source,
 				     locp->first_line,
-- 
1.7.10



More information about the mesa-dev mailing list