[Mesa-dev] [PATCH 1/2] glsl: Support GL_ARB_shading_language_include internally.

Olivier Galibert galibert at pobox.com
Wed Apr 11 01:46:51 PDT 2012


No hookup with GL yet.  Planned to be used to simplify profiles.

Signed-off-by: Olivier Galibert <galibert at pobox.com>
---
 src/glsl/ast.h                  |   12 ++-
 src/glsl/glcpp/glcpp-lex.l      |  135 ++++++++++++++++++++++++--
 src/glsl/glcpp/glcpp-parse.y    |   75 +++++++++++++-
 src/glsl/glcpp/glcpp.c          |   14 +++-
 src/glsl/glcpp/glcpp.h          |   56 ++++++++++-
 src/glsl/glcpp/pp.c             |   92 ++++++++++++++++-
 src/glsl/glsl_lexer.ll          |   32 ++++++-
 src/glsl/glsl_parser.yy         |  203 ++++++++++++++++++++-------------------
 src/glsl/glsl_parser_extras.cpp |   23 ++++-
 src/glsl/glsl_parser_extras.h   |   16 +++-
 src/glsl/main.cpp               |   24 ++++-
 src/glsl/test_optpass.cpp       |    2 +-
 src/mesa/program/ir_to_mesa.cpp |    2 +-
 13 files changed, 542 insertions(+), 144 deletions(-)

diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index 1f78af8..b0bfb28 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -65,6 +65,9 @@ public:
     * ralloc_free in that case. */
    static void operator delete(void *table)
    {
+      ast_node *an = static_cast<ast_node *>(table);
+      if(an->location.source)
+	 ralloc_free(an->location.source);
       ralloc_free(table);
    }
 
@@ -92,6 +95,7 @@ public:
       struct YYLTYPE locp;
 
       locp.source = this->location.source;
+      locp.source_id = this->location.source_id;
       locp.first_line = this->location.line;
       locp.first_column = this->location.column;
       locp.last_line = locp.first_line;
@@ -105,9 +109,10 @@ public:
     *
     * \sa ast_node::get_location
     */
-   void set_location(const struct YYLTYPE &locp)
+   void set_location(const struct YYLTYPE &locp, void *ctx)
    {
-      this->location.source = locp.source;
+      this->location.source = locp.source ? ralloc_strdup(ctx, locp.source) : 0;
+      this->location.source_id = locp.source_id;
       this->location.line = locp.first_line;
       this->location.column = locp.first_column;
    }
@@ -116,7 +121,8 @@ public:
     * Source location of the AST node.
     */
    struct {
-      unsigned source;    /**< GLSL source number. */
+      unsigned source_id; /**< GLSL source number (if source is NULL)  */
+      char *source;       /**< GLSL source file or NULL */
       unsigned line;      /**< Line number within the source string. */
       unsigned column;    /**< Column in the line. */
    } location;
diff --git a/src/glsl/glcpp/glcpp-lex.l b/src/glsl/glcpp/glcpp-lex.l
index b34f2c0..2ce1547 100644
--- a/src/glsl/glcpp/glcpp-lex.l
+++ b/src/glsl/glcpp/glcpp-lex.l
@@ -44,6 +44,8 @@ void glcpp_set_column (int  column_no , yyscan_t yyscanner);
    do {                                                         \
       yylloc->first_column = yycolumn + 1;                      \
       yylloc->first_line = yylineno;                            \
+      yylloc->source = yyextra->source;                         \
+      yylloc->source_id = yyextra->source_id;                   \
       yycolumn += yyleng;                                       \
    } while(0);
 
@@ -51,17 +53,16 @@ void glcpp_set_column (int  column_no , yyscan_t yyscanner);
 	do {				\
 		yylineno = 1;		\
 		yycolumn = 1;		\
-		yylloc->source = 0;	\
 	} while(0)
 %}
 
-%option bison-bridge bison-locations reentrant noyywrap
+%option bison-bridge bison-locations reentrant
 %option extra-type="glcpp_parser_t *"
 %option prefix="glcpp_"
 %option stack
 %option never-interactive
 
-%x DONE COMMENT UNREACHABLE SKIP
+%x DONE COMMENT UNREACHABLE SKIP EXTENSION
 
 SPACE		[[:space:]]
 NONSPACE	[^[:space:]]
@@ -69,7 +70,8 @@ NEWLINE		[\n]
 HSPACE		[ \t]
 HASH		^{HSPACE}*#{HSPACE}*
 IDENTIFIER	[_a-zA-Z][_a-zA-Z0-9]*
-PUNCTUATION	[][(){}.&*~!/%<>^|;,=+-]
+PUNCTUATION	[][(){}.&*~!/%<>^|;,=+-:]
+STRING		"\""[^"\n]+"\""
 
 /* The OTHER class is simply a catch-all for things that the CPP
 parser just doesn't care about. Since flex regular expressions that
@@ -78,7 +80,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,15 +122,45 @@ HEXADECIMAL_INTEGER	0[xX][0-9a-fA-F]+[uU]?
 	return HASH_VERSION;
 }
 
-	/* glcpp doesn't handle #extension, #version, or #pragma directives.
+{HASH}extension{HSPACE}+ {
+	return HASH_EXTENSION;
+}
+
+	/* glcpp doesn't handle #pragma directives.
 	 * Simply pass them through to the main compiler's lexer/parser. */
-{HASH}(extension|pragma)[^\n]+ {
+{HASH}pragma[^\n]+ {
 	yylval->str = ralloc_strdup (yyextra, yytext);
 	yylineno++;
 	yycolumn = 0;
 	return OTHER;
 }
 
+{HASH}include{HSPACE}*{STRING}{HSPACE}*$ {
+	char *ptr = yytext;
+	while (*ptr != '"')
+		ptr++;
+	ptr++;
+	char *eptr = ptr;
+	while (*eptr != '"')
+		eptr++;
+	*eptr = 0;
+	yylval->str = ralloc_strdup (yyextra, ptr);
+	return HASH_INCLUDE;
+}
+
+{HASH}include{HSPACE}*<[^>\n]>+{HSPACE}*$ {
+	char *ptr = yytext;
+	while (*ptr != '<')
+		ptr++;
+	ptr++;
+	char *eptr = ptr;
+	while (*eptr != '>')
+		eptr++;
+	*eptr = 0;
+	yylval->str = ralloc_strdup (yyextra, ptr);
+	return HASH_INCLUDE;
+}
+
 {HASH}line{HSPACE}+{DIGITS}{HSPACE}+{DIGITS}{HSPACE}*$ {
 	/* Eat characters until the first digit is
 	 * encountered
@@ -142,7 +174,33 @@ HEXADECIMAL_INTEGER	0[xX][0-9a-fA-F]+[uU]?
 	 * one-based.
 	 */
 	yylineno = strtol(ptr, &ptr, 0) - 1;
-	yylloc->source = strtol(ptr, NULL, 0);
+	yyextra->source_id = yylloc->source_id = strtol(ptr, NULL, 0);
+	yyextra->source = yylloc->source = 0;
+}
+
+{HASH}line{HSPACE}+{DIGITS}{HSPACE}+{STRING}{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;
+
+	while (*ptr != '"')
+		ptr++;
+	ptr++;
+	char *eptr = ptr;
+	while (*eptr != '"')
+		eptr++;
+	*eptr = 0;
+	yyextra->source_id = yylloc->source_id = 0;
+	yyextra->source = yylloc->source = ralloc_strdup(yyextra, ptr);
 }
 
 {HASH}line{HSPACE}+{DIGITS}{HSPACE}*$ {
@@ -328,5 +386,64 @@ HEXADECIMAL_INTEGER	0[xX][0-9a-fA-F]+[uU]?
 void
 glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader)
 {
-	yy_scan_string(shader, parser->scanner);
+	parser->current_buffer = yy_scan_string(shader, parser->scanner);
+	glcpp_set_lineno (1, parser->scanner);
+}
+
+
+void
+glcpp_push_input (glcpp_parser_t *parser, const char *data, const char *base_path, const char *file_name)
+{
+	struct glcpp_parser_input_file *is = ralloc (parser, struct glcpp_parser_input_file);
+	is->base_path = parser->base_path;
+	is->buffer = parser->current_buffer;
+	is->prev = parser->input_stack;
+
+	is->source = parser->source;
+	is->source_id = parser->source_id;
+
+	parser->input_stack = is;
+
+	parser->base_path = base_path;
+	glcpp_lex_set_source_string(parser, data);
+
+	parser->source = file_name;
+	parser->source_id = 0;
+}
+
+int
+glcpp_wrap (yyscan_t scanner)
+{
+	glcpp_parser_t *parser = glcpp_get_extra (scanner);
+	if (glcpp_input_stack_empty (parser))
+		return 1;
+	glcpp_pop_input (parser);
+	return 0;
+}
+
+int
+glcpp_input_stack_empty (glcpp_parser_t *parser)
+{
+	return !parser->input_stack;
+}
+
+void
+glcpp_pop_input (glcpp_parser_t *parser)
+{
+	struct glcpp_parser_input_file *is = parser->input_stack;
+	parser->input_stack = is->prev;
+	parser->base_path = is->base_path;
+	yy_delete_buffer(parser->current_buffer, parser->scanner);
+	parser->current_buffer = is->buffer;
+	yy_switch_to_buffer (parser->current_buffer, parser->scanner);
+
+	parser->source = is->source;
+	parser->source_id = is->source_id;
+
+	if (parser->source)
+		ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "#line %d \"%s\"\n", glcpp_get_lineno (parser->scanner)-1, parser->source);
+	else
+		ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "#line %d %d\n", glcpp_get_lineno (parser->scanner)-1, parser->source_id);
+
+	ralloc_free (is);
 }
diff --git a/src/glsl/glcpp/glcpp-parse.y b/src/glsl/glcpp/glcpp-parse.y
index 47ba54d..ec94290 100644
--- a/src/glsl/glcpp/glcpp-parse.y
+++ b/src/glsl/glcpp/glcpp-parse.y
@@ -150,16 +150,17 @@ add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
 	@$.last_line = 1;
 	@$.last_column = 1;
 	@$.source = 0;
+	@$.source_id = 0;
 }
 
 %parse-param {glcpp_parser_t *parser}
 %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 PASTE
+%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 HASH_INCLUDE HASH_EXTENSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE
+%token PASTE ':'
 %type <ival> expression INTEGER operator SPACE integer_constant
-%type <str> IDENTIFIER INTEGER_STRING OTHER
+%type <str> IDENTIFIER INTEGER_STRING OTHER HASH_INCLUDE
 %type <string_list> identifier_list
 %type <token> preprocessing_token conditional_token
 %type <token_list> pp_tokens replacement_list text_line conditional_tokens
@@ -193,6 +194,8 @@ line:
 	}
 |	expanded_line
 |	HASH non_directive
+|	extension_line
+|	include_line
 ;
 
 expanded_line:
@@ -325,6 +328,59 @@ control_line:
 |	HASH NEWLINE
 ;
 
+extension_line:
+	HASH_EXTENSION IDENTIFIER space_or_nothing ':' space_or_nothing IDENTIFIER space_or_nothing NEWLINE {
+		if (!strcmp ($2, "GL_ARB_shading_language_include")) {
+			if (!strcmp ($6, "enable") || !strcmp($6, "require"))
+				parser->include_mode = INCLUDE_OK;
+			else if (!strcmp ($6, "disable"))
+				parser->include_mode = INCLUDE_DISABLED;
+			else if (!strcmp ($6, "warn"))
+				parser->include_mode = INCLUDE_WARN;
+			else
+				yyerror (& @6, parser, "Unknown extension behavior");
+		}
+		else
+		{
+			if (!strcmp ($2, "all")) {
+				if (!strcmp ($6, "warn"))
+					parser->include_mode = INCLUDE_WARN;
+				else if (!strcmp ($6, "disable"))
+					parser->include_mode = INCLUDE_DISABLED;
+			}
+			ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "#extension %s : %s\n", $2, $6);
+			ralloc_free ($2);
+			ralloc_free ($6);
+		}
+	}
+;
+
+include_line:
+	HASH_INCLUDE {
+		if (parser->include_mode == INCLUDE_DISABLED)
+			glcpp_error (&@1, parser, "#include encountered with GL_ARB_shading_language_include disabled\n");
+		else
+		{
+			if (parser->include_mode == INCLUDE_WARN)
+				glcpp_error (&@1, parser, "#include encountered with GL_ARB_shading_language_include set to warn\n");
+			char *new_base_path = glcpp_canonicalize_path (parser, parser->base_path, $1);
+			char *new_file_name = glcpp_add_file_name (parser, new_base_path, $1);
+			const char *subshader = parser->include_get_string (parser->include_param, new_file_name);
+			if (!subshader)
+				glcpp_error (&@1, parser, "Could not find string for inclusion: %s\n", new_file_name);
+			else {
+				ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "#line 1 \"%s\"\n", new_file_name);
+				glcpp_push_input (parser, subshader, new_base_path, new_file_name);
+			}
+		}
+	}
+;
+
+space_or_nothing:
+	SPACE
+|	/* empty */
+;
+
 integer_constant:
 	INTEGER_STRING {
 		if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) {
@@ -551,7 +607,6 @@ operator:
 |	'='			{ $$ = '='; }
 |	PASTE			{ $$ = PASTE; }
 ;
-
 %%
 
 string_list_t *
@@ -1081,7 +1136,9 @@ static void add_builtin_define(glcpp_parser_t *parser,
 }
 
 glcpp_parser_t *
-glcpp_parser_create (const struct gl_extensions *extensions, int api)
+glcpp_parser_create (const struct gl_extensions *extensions, int api,
+	   const char *base_path,
+	   const char *(*get_string)(void *param, const char *), void *param)
 {
 	glcpp_parser_t *parser;
 	int language_version;
@@ -1097,6 +1154,13 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
 	parser->newline_as_space = 0;
 	parser->in_control_line = 0;
 	parser->paren_count = 0;
+	parser->include_mode = INCLUDE_DISABLED;
+	parser->base_path = base_path;
+	parser->include_get_string = get_string;
+	parser->include_param = param;
+	parser->input_stack = NULL;
+	parser->source = 0;
+	parser->source_id = 0;
 
 	parser->skip_stack = NULL;
 
@@ -1763,7 +1827,6 @@ glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
 
 	if (parser->lex_from_list == NULL) {
 		ret = glcpp_lex (yylval, yylloc, parser->scanner);
-
 		/* XXX: This ugly block of code exists for the sole
 		 * purpose of converting a NEWLINE token into a SPACE
 		 * token, but only in the case where we have seen a
diff --git a/src/glsl/glcpp/glcpp.c b/src/glsl/glcpp/glcpp.c
index e461a65..8fce570 100644
--- a/src/glsl/glcpp/glcpp.c
+++ b/src/glsl/glcpp/glcpp.c
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <unistd.h>
 #include "glcpp.h"
 #include "main/mtypes.h"
 #include "main/shaderobj.h"
@@ -94,6 +95,12 @@ load_text_file(void *ctx, const char *filename)
 	return text;
 }
 
+static const char *
+get_string (void *ctx, const char *name)
+{
+	return load_text_file(ctx, name);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -107,11 +114,16 @@ main (int argc, char *argv[])
 		filename = argv[1];
 	}
 
+	char *cur_dir = get_current_dir_name();
+	char *base_path = glcpp_canonicalize_path(NULL, cur_dir, filename ? filename : "");
+	free(cur_dir);
+
 	shader = load_text_file (ctx, filename);
 	if (shader == NULL)
 	   return 1;
 
-	ret = preprocess(ctx, &shader, &info_log, NULL, API_OPENGL);
+	ret = preprocess(ctx, &shader, &info_log, NULL, API_OPENGL, base_path, get_string, ctx);
+	ralloc_free(base_path);
 
 	printf("%s", shader);
 	fprintf(stderr, "%s", info_log);
diff --git a/src/glsl/glcpp/glcpp.h b/src/glsl/glcpp/glcpp.h
index 2d7cad2..ebcd90b 100644
--- a/src/glsl/glcpp/glcpp.h
+++ b/src/glsl/glcpp/glcpp.h
@@ -64,10 +64,11 @@ typedef struct YYLTYPE {
    int first_column;
    int last_line;
    int last_column;
-   unsigned source;
+   const char *source;
+   unsigned source_id;
 } YYLTYPE;
 # define YYLTYPE_IS_DECLARED 1
-# define YYLTYPE_IS_TRIVIAL 1
+# undef YYLTYPE_IS_TRIVIAL
 
 # define YYLLOC_DEFAULT(Current, Rhs, N)			\
 do {								\
@@ -77,6 +78,8 @@ do {								\
       (Current).first_column = YYRHSLOC(Rhs, 1).first_column;	\
       (Current).last_line    = YYRHSLOC(Rhs, N).last_line;	\
       (Current).last_column  = YYRHSLOC(Rhs, N).last_column;	\
+      (Current).source       = YYRHSLOC(Rhs, 1).source;         \
+      (Current).source_id    = YYRHSLOC(Rhs, 1).source_id;      \
    }								\
    else								\
    {								\
@@ -84,6 +87,8 @@ do {								\
 	 YYRHSLOC(Rhs, 0).last_line;				\
       (Current).first_column = (Current).last_column =		\
 	 YYRHSLOC(Rhs, 0).last_column;				\
+      (Current).source       = YYRHSLOC(Rhs, 0).source;         \
+      (Current).source_id    = YYRHSLOC(Rhs, 0).source_id;      \
    }								\
    (Current).source = 0;					\
 } while (0)
@@ -160,6 +165,20 @@ typedef struct active_list {
 	struct active_list *next;
 } active_list_t;
 
+typedef enum {
+	INCLUDE_DISABLED,
+	INCLUDE_WARN,
+	INCLUDE_OK
+} include_mode_t;
+
+struct glcpp_parser_input_file {
+	struct glcpp_parser_input_file *prev;
+	struct yy_buffer_state *buffer;
+	const char *base_path;
+	const char *source;
+	unsigned source_id;
+};
+
 struct glcpp_parser {
 	yyscan_t scanner;
 	struct hash_table *defines;
@@ -169,6 +188,7 @@ struct glcpp_parser {
 	int newline_as_space;
 	int in_control_line;
 	int paren_count;
+	include_mode_t include_mode;
 	skip_node_t *skip_stack;
 	token_list_t *lex_from_list;
 	token_node_t *lex_from_node;
@@ -177,12 +197,21 @@ struct glcpp_parser {
 	size_t output_length;
 	size_t info_log_length;
 	int error;
+	unsigned int source_id;
+	const char *base_path;
+	const char *source;
+	const char *(*include_get_string)(void *param, const char *);
+	void *include_param;
+	struct yy_buffer_state *current_buffer;
+	struct glcpp_parser_input_file *input_stack;
 };
 
 struct gl_extensions;
 
 glcpp_parser_t *
-glcpp_parser_create (const struct gl_extensions *extensions, int api);
+glcpp_parser_create (const struct gl_extensions *extensions, int api,
+		     const char *base_path,
+		     const char *(*get_string)(void *param, const char *), void *param);
 
 int
 glcpp_parser_parse (glcpp_parser_t *parser);
@@ -192,7 +221,9 @@ glcpp_parser_destroy (glcpp_parser_t *parser);
 
 int
 preprocess(void *ralloc_ctx, const char **shader, char **info_log,
-	   const struct gl_extensions *extensions, int api);
+	   const struct gl_extensions *extensions, int api,
+	   const char *base_path,
+	   const char *(*get_string)(void *param, const char *), void *param);
 
 /* Functions for writing to the info log */
 
@@ -202,6 +233,23 @@ glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...);
 void
 glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...);
 
+/* Functions for include support */
+
+char *
+glcpp_canonicalize_path (void *ctx, const char *base_path, const char *file_name);
+
+char *
+glcpp_add_file_name (void *ctx, const char *base_path, const char *file_name);
+
+void
+glcpp_push_input (glcpp_parser_t *parser, const char *data, const char *base_path, const char *file_name);
+
+int
+glcpp_input_stack_empty (glcpp_parser_t *parser);
+
+void
+glcpp_pop_input (glcpp_parser_t *parser);
+
 /* Generated by glcpp-lex.l to glcpp-lex.c */
 
 int
diff --git a/src/glsl/glcpp/pp.c b/src/glsl/glcpp/pp.c
index 3640896..10c239c 100644
--- a/src/glsl/glcpp/pp.c
+++ b/src/glsl/glcpp/pp.c
@@ -32,10 +32,17 @@ glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
 {
 	va_list ap;
 
+	char sbuf[12];
+	const char *source = locp->source;
+	if (!source) {
+		source = sbuf;
+		sprintf (sbuf, "%u", locp->source_id);
+	}
+
 	parser->error = 1;
-	ralloc_asprintf_append(&parser->info_log, "%u:%u(%u): "
+	ralloc_asprintf_append(&parser->info_log, "%s:%u(%u): "
 						  "preprocessor error: ",
-						  locp->source,
+						  source,
 						  locp->first_line,
 						  locp->first_column);
 	va_start(ap, fmt);
@@ -49,9 +56,15 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
 {
 	va_list ap;
 
-	ralloc_asprintf_append(&parser->info_log, "%u:%u(%u): "
+	char sbuf[12];
+	const char *source = locp->source;
+	if (!source) {
+		source = sbuf;
+		sprintf (sbuf, "%u", locp->source_id);
+	}
+	ralloc_asprintf_append(&parser->info_log, "%s:%u(%u): "
 						  "preprocessor warning: ",
-						  locp->source,
+						  source,
 						  locp->first_line,
 						  locp->first_column);
 	va_start(ap, fmt);
@@ -60,6 +73,71 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
 	ralloc_strcat(&parser->info_log, "\n");
 }
 
+char *
+glcpp_canonicalize_path(void *ctx, const char *base_path, const char *file_name)
+{
+	if(file_name[0] == '/')
+		base_path = "";
+
+	char *res = ralloc_size(ctx, strlen(base_path) + strlen(file_name) + 2);
+	sprintf(res, "%s/%s", base_path, file_name);
+
+	// Cleanup //, . and .. and final file name
+
+	// base_path, and hence the buffer, will always start with '/'
+
+	// rp is the current read position, prp is the position of the
+	// first character after the previous '/', wp is the (re)write
+	// position
+
+	const char *rp = res+1;
+	const char *prp = res+1;
+	char *wp = res;
+	while(*rp) {
+		if(*rp == '/') {
+			// Eliminate successions of '/'
+			if(rp == prp) {
+			}
+			// Drop '.'
+			else if(rp == prp+1 && prp[0] == '.') {
+			}
+			// Rewind one level on '..', don't go past the beginning of buffer
+			else if(rp == prp+2 && prp[0] == '.' && prp[1] == '.') {
+				while(wp != res && wp[-1] != '/')
+					wp--;
+			}
+			// Copy path element
+			else
+			{
+				*wp++ = '/';
+				while(prp != rp)
+					*wp++ = *prp++;
+			}
+			rp++;
+			prp = rp;
+		}
+		else
+			rp++;
+	}
+	*wp = 0;
+
+	return res;
+}
+
+char *
+glcpp_add_file_name(void *ctx, const char *base_path, const char *file_name)
+{
+	const char *slash_pos = strrchr(file_name, '/');
+	if(slash_pos)
+		slash_pos++;
+	else
+		slash_pos = file_name;
+
+	char *res = ralloc_size(ctx, strlen(base_path) + strlen(slash_pos) + 2);
+	sprintf(res, "%s/%s", base_path, slash_pos);
+	return res;
+}
+
 /* Searches backwards for '^ *#' from a given starting point. */
 static int
 in_directive(const char *shader, const char *ptr)
@@ -141,10 +219,12 @@ remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
 
 int
 preprocess(void *ralloc_ctx, const char **shader, char **info_log,
-	   const struct gl_extensions *extensions, int api)
+	   const struct gl_extensions *extensions, int api,
+	   const char *base_path,
+	   const char *(*get_string)(void *param, const char *), void *param)
 {
 	int errors;
-	glcpp_parser_t *parser = glcpp_parser_create (extensions, api);
+	glcpp_parser_t *parser = glcpp_parser_create (extensions, api, base_path, get_string, param);
 	*shader = remove_line_continuations(parser, *shader);
 
 	glcpp_lex_set_source_string (parser, *shader);
diff --git a/src/glsl/glsl_lexer.ll b/src/glsl/glsl_lexer.ll
index 936a907..b604ce6 100644
--- a/src/glsl/glsl_lexer.ll
+++ b/src/glsl/glsl_lexer.ll
@@ -36,7 +36,8 @@ static int classify_identifier(struct _mesa_glsl_parse_state *, const char *);
 
 #define YY_USER_ACTION						\
    do {								\
-      yylloc->source = 0;					\
+      yylloc->source = yyextra->source;				\
+      yylloc->source_id = yyextra->source_id;			\
       yylloc->first_column = yycolumn + 1;			\
       yylloc->first_line = yylineno + 1;			\
       yycolumn += yyleng;					\
@@ -142,6 +143,7 @@ INT		({DEC_INT}|{HEX_INT}|{OCT_INT})
 SPC		[ \t]*
 SPCP		[ \t]+
 HASH		^{SPC}#{SPC}
+STR		"\""[^"\n]+"\""
 %%
 
 [ \r\t]+		;
@@ -163,7 +165,33 @@ HASH		^{SPC}#{SPC}
 				    * one-based.
 				    */
 				   yylineno = strtol(ptr, &ptr, 0) - 1;
-				   yylloc->source = strtol(ptr, NULL, 0);
+				   yyextra->source_id = yylloc->source_id = strtol(ptr, NULL, 0);
+				   yyextra->source = yylloc->source = 0;
+				}
+{HASH}line{SPCP}{INT}{SPCP}{STR}{SPC}$ {
+				   /* Eat characters until the first digit is
+				    * encountered
+				    */
+				   char *ptr = yytext;
+				   while (!isdigit(*ptr))
+				      ptr++;
+
+				   while (*ptr != '"')
+				      ptr++;
+				   ptr++;
+				   char *eptr = ptr;
+				   while (*eptr != '"')
+				      eptr++;
+				   *eptr = 0;
+
+				   yyextra->source_id = yylloc->source_id = 0;
+				   yyextra->source = yylloc->source = strdup(ptr);
+// must use ralloc_strdup
+				   /* Subtract one from the line number because
+				    * yylineno is zero-based instead of
+				    * one-based.
+				    */
+				   yylineno = strtol(ptr, &ptr, 0) - 1;
 				}
 {HASH}line{SPCP}{INT}{SPC}$	{
 				   /* Eat characters until the first digit is
diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
index 9a0af95..ac834eb 100644
--- a/src/glsl/glsl_parser.yy
+++ b/src/glsl/glsl_parser.yy
@@ -50,6 +50,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
    @$.last_line = 1;
    @$.last_column = 1;
    @$.source = 0;
+   @$.source_id = 0;
 }
 
 %lex-param   {void *scanner}
@@ -353,35 +354,35 @@ primary_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_identifier, NULL, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->primary_expression.identifier = $1;
 	}
 	| INTCONSTANT
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_int_constant, NULL, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->primary_expression.int_constant = $1;
 	}
 	| UINTCONSTANT
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_uint_constant, NULL, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->primary_expression.uint_constant = $1;
 	}
 	| FLOATCONSTANT
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_float_constant, NULL, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->primary_expression.float_constant = $1;
 	}
 	| BOOLCONSTANT
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_bool_constant, NULL, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->primary_expression.bool_constant = $1;
 	}
 	| '(' expression ')'
@@ -396,7 +397,7 @@ postfix_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_array_index, $1, $3, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| function_call
 	{
@@ -406,20 +407,20 @@ postfix_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_field_selection, $1, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->primary_expression.identifier = $3;
 	}
 	| postfix_expression INC_OP
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_post_inc, $1, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| postfix_expression DEC_OP
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_post_dec, $1, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -437,7 +438,7 @@ function_call_or_method:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_field_selection, $1, $3, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -455,13 +456,13 @@ function_call_header_with_parameters:
 	function_call_header assignment_expression
 	{
 	   $$ = $1;
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	   $$->expressions.push_tail(& $2->link);
 	}
 	| function_call_header_with_parameters ',' assignment_expression
 	{
 	   $$ = $1;
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	   $$->expressions.push_tail(& $3->link);
 	}
 	;
@@ -478,21 +479,21 @@ function_identifier:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_function_expression($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
    	}
 	| variable_identifier
 	{
 	   void *ctx = state;
 	   ast_expression *callee = new(ctx) ast_expression($1);
 	   $$ = new(ctx) ast_function_expression(callee);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
    	}
 	| FIELD_SELECTION
 	{
 	   void *ctx = state;
 	   ast_expression *callee = new(ctx) ast_expression($1);
 	   $$ = new(ctx) ast_function_expression(callee);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
    	}
 	;
 
@@ -510,13 +511,13 @@ method_call_header_with_parameters:
 	method_call_header assignment_expression
 	{
 	   $$ = $1;
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	   $$->expressions.push_tail(& $2->link);
 	}
 	| method_call_header_with_parameters ',' assignment_expression
 	{
 	   $$ = $1;
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	   $$->expressions.push_tail(& $3->link);
 	}
 	;
@@ -530,7 +531,7 @@ method_call_header:
 	   void *ctx = state;
 	   ast_expression *callee = new(ctx) ast_expression($1);
 	   $$ = new(ctx) ast_function_expression(callee);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
    	}
 	;
 
@@ -541,19 +542,19 @@ unary_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_pre_inc, $2, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| DEC_OP unary_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_pre_dec, $2, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| unary_operator unary_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression($1, $2, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -571,19 +572,19 @@ multiplicative_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_mul, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| multiplicative_expression '/' unary_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_div, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| multiplicative_expression '%' unary_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_mod, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -593,13 +594,13 @@ additive_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_add, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| additive_expression '-' multiplicative_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_sub, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -609,13 +610,13 @@ shift_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_lshift, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| shift_expression RIGHT_OP additive_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_rshift, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -625,25 +626,25 @@ relational_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_less, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| relational_expression '>' shift_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_greater, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| relational_expression LE_OP shift_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_lequal, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| relational_expression GE_OP shift_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_gequal, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -653,13 +654,13 @@ equality_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_equal, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| equality_expression NE_OP relational_expression
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_nequal, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -669,7 +670,7 @@ and_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_bit_and, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -679,7 +680,7 @@ exclusive_or_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_bit_xor, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -689,7 +690,7 @@ inclusive_or_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_bit_or, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -699,7 +700,7 @@ logical_and_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_logic_and, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -709,7 +710,7 @@ logical_xor_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_logic_xor, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -719,7 +720,7 @@ logical_or_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_bin(ast_logic_or, $1, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -729,7 +730,7 @@ conditional_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression(ast_conditional, $1, $3, $5);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -739,7 +740,7 @@ assignment_expression:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression($2, $1, $3, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -767,7 +768,7 @@ expression:
 	   void *ctx = state;
 	   if ($1->oper != ast_sequence) {
 	      $$ = new(ctx) ast_expression(ast_sequence, NULL, NULL, NULL);
-	      $$->set_location(yylloc);
+	      $$->set_location(yylloc, ctx);
 	      $$->expressions.push_tail(& $1->link);
 	   } else {
 	      $$ = $1;
@@ -826,7 +827,7 @@ function_header:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_function();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->return_type = $1;
 	   $$->identifier = $2;
 
@@ -840,9 +841,9 @@ parameter_declarator:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_parameter_declarator();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->type = new(ctx) ast_fully_specified_type();
-	   $$->type->set_location(yylloc);
+	   $$->type->set_location(yylloc, ctx);
 	   $$->type->specifier = $1;
 	   $$->identifier = $2;
 	}
@@ -850,9 +851,9 @@ parameter_declarator:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_parameter_declarator();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->type = new(ctx) ast_fully_specified_type();
-	   $$->type->set_location(yylloc);
+	   $$->type->set_location(yylloc, ctx);
 	   $$->type->specifier = $1;
 	   $$->identifier = $2;
 	   $$->is_array = true;
@@ -879,7 +880,7 @@ parameter_declaration:
 	   $1.flags.i |= $2.flags.i;
 
 	   $$ = new(ctx) ast_parameter_declarator();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->type = new(ctx) ast_fully_specified_type();
 	   $$->type->qualifier = $1;
 	   $$->type->specifier = $3;
@@ -888,7 +889,7 @@ parameter_declaration:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_parameter_declarator();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->type = new(ctx) ast_fully_specified_type();
 	   $$->type->qualifier = $1;
 	   $$->type->specifier = $2;
@@ -928,7 +929,7 @@ init_declarator_list:
 	{
 	   void *ctx = state;
 	   ast_declaration *decl = new(ctx) ast_declaration($3, false, NULL, NULL);
-	   decl->set_location(yylloc);
+	   decl->set_location(yylloc, ctx);
 
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
@@ -938,7 +939,7 @@ init_declarator_list:
 	{
 	   void *ctx = state;
 	   ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, NULL);
-	   decl->set_location(yylloc);
+	   decl->set_location(yylloc, ctx);
 
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
@@ -948,7 +949,7 @@ init_declarator_list:
 	{
 	   void *ctx = state;
 	   ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, NULL);
-	   decl->set_location(yylloc);
+	   decl->set_location(yylloc, ctx);
 
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
@@ -958,7 +959,7 @@ init_declarator_list:
 	{
 	   void *ctx = state;
 	   ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, $7);
-	   decl->set_location(yylloc);
+	   decl->set_location(yylloc, ctx);
 
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
@@ -968,7 +969,7 @@ init_declarator_list:
 	{
 	   void *ctx = state;
 	   ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, $8);
-	   decl->set_location(yylloc);
+	   decl->set_location(yylloc, ctx);
 
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
@@ -978,7 +979,7 @@ init_declarator_list:
 	{
 	   void *ctx = state;
 	   ast_declaration *decl = new(ctx) ast_declaration($3, false, NULL, $5);
-	   decl->set_location(yylloc);
+	   decl->set_location(yylloc, ctx);
 
 	   $$ = $1;
 	   $$->declarations.push_tail(&decl->link);
@@ -993,7 +994,7 @@ single_declaration:
 	   void *ctx = state;
 	   /* Empty declaration list is valid. */
 	   $$ = new(ctx) ast_declarator_list($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| fully_specified_type any_identifier
 	{
@@ -1001,7 +1002,7 @@ single_declaration:
 	   ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, NULL);
 
 	   $$ = new(ctx) ast_declarator_list($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->declarations.push_tail(&decl->link);
 	}
 	| fully_specified_type any_identifier '[' ']'
@@ -1010,7 +1011,7 @@ single_declaration:
 	   ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, NULL);
 
 	   $$ = new(ctx) ast_declarator_list($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->declarations.push_tail(&decl->link);
 	}
 	| fully_specified_type any_identifier '[' constant_expression ']'
@@ -1019,7 +1020,7 @@ single_declaration:
 	   ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, NULL);
 
 	   $$ = new(ctx) ast_declarator_list($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->declarations.push_tail(&decl->link);
 	}
 	| fully_specified_type any_identifier '[' ']' '=' initializer
@@ -1028,7 +1029,7 @@ single_declaration:
 	   ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, $6);
 
 	   $$ = new(ctx) ast_declarator_list($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->declarations.push_tail(&decl->link);
 	}
 	| fully_specified_type any_identifier '[' constant_expression ']' '=' initializer
@@ -1037,7 +1038,7 @@ single_declaration:
 	   ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, $7);
 
 	   $$ = new(ctx) ast_declarator_list($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->declarations.push_tail(&decl->link);
 	}
 	| fully_specified_type any_identifier '=' initializer
@@ -1046,7 +1047,7 @@ single_declaration:
 	   ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, $4);
 
 	   $$ = new(ctx) ast_declarator_list($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->declarations.push_tail(&decl->link);
 	}
 	| INVARIANT variable_identifier // Vertex only.
@@ -1055,7 +1056,7 @@ single_declaration:
 	   ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, NULL);
 
 	   $$ = new(ctx) ast_declarator_list(NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->invariant = true;
 
 	   $$->declarations.push_tail(&decl->link);
@@ -1067,14 +1068,14 @@ fully_specified_type:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_fully_specified_type();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->specifier = $1;
 	}
 	| type_qualifier type_specifier
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_fully_specified_type();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->qualifier = $1;
 	   $$->specifier = $2;
 	}
@@ -1347,19 +1348,19 @@ type_specifier_nonarray:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_type_specifier($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| struct_specifier
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_type_specifier($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| TYPE_IDENTIFIER
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_type_specifier($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -1456,14 +1457,14 @@ struct_specifier:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_struct_specifier($2, $4);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   state->symbols->add_type($2, glsl_type::void_type);
 	}
 	| STRUCT '{' struct_declaration_list '}'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_struct_specifier(NULL, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -1485,11 +1486,11 @@ struct_declaration:
 	{
 	   void *ctx = state;
 	   ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
-	   type->set_location(yylloc);
+	   type->set_location(yylloc, ctx);
 
 	   type->specifier = $1;
 	   $$ = new(ctx) ast_declarator_list(type);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 
 	   $$->declarations.push_degenerate_list_at_head(& $2->link);
 	}
@@ -1513,14 +1514,14 @@ struct_declarator:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_declaration($1, false, NULL, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   state->symbols->add_variable(new(state) ir_variable(NULL, $1, ir_var_auto));
 	}
 	| any_identifier '[' constant_expression ']'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_declaration($1, true, $3, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -1553,7 +1554,7 @@ compound_statement:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_compound_statement(true, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| '{'
 	{
@@ -1563,7 +1564,7 @@ compound_statement:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_compound_statement(true, $3);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   state->symbols->pop_scope();
 	}
 	;
@@ -1578,13 +1579,13 @@ compound_statement_no_new_scope:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_compound_statement(false, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| '{' statement_list '}'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_compound_statement(false, $2);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -1615,13 +1616,13 @@ expression_statement:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_statement(NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| expression ';'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_expression_statement($1);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -1630,7 +1631,7 @@ selection_statement:
 	{
 	   $$ = new(state) ast_selection_statement($3, $5.then_statement,
 						   $5.else_statement);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	}
 	;
 
@@ -1657,8 +1658,8 @@ condition:
 	   void *ctx = state;
 	   ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, $4);
 	   ast_declarator_list *declarator = new(ctx) ast_declarator_list($1);
-	   decl->set_location(yylloc);
-	   declarator->set_location(yylloc);
+	   decl->set_location(yylloc, ctx);
+	   declarator->set_location(yylloc, ctx);
 
 	   declarator->declarations.push_tail(&decl->link);
 	   $$ = declarator;
@@ -1673,7 +1674,7 @@ switch_statement:
 	SWITCH '(' expression ')' switch_body
 	{
 	   $$ = new(state) ast_switch_statement($3, $5);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	}
 	;
 
@@ -1681,12 +1682,12 @@ switch_body:
 	'{' '}'
 	{
 	   $$ = new(state) ast_switch_body(NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	}
 	| '{' case_statement_list '}'
 	{
 	   $$ = new(state) ast_switch_body($2);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	}
 	;
 
@@ -1694,12 +1695,12 @@ case_label:
 	CASE expression ':'
 	{
 	   $$ = new(state) ast_case_label($2);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	}
 	| DEFAULT ':'
 	{
 	   $$ = new(state) ast_case_label(NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	}
 	;
 
@@ -1710,7 +1711,7 @@ case_label_list:
 
 	   labels->labels.push_tail(& $1->link);
 	   $$ = labels;
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, state);
 	}
 	| case_label_list case_label
 	{
@@ -1723,7 +1724,7 @@ case_statement:
 	case_label_list statement
 	{
 	   ast_case_statement *stmts = new(state) ast_case_statement($1);
-	   stmts->set_location(yylloc);
+	   stmts->set_location(yylloc, state);
 
 	   stmts->stmts.push_tail(& $2->link);
 	   $$ = stmts;
@@ -1739,7 +1740,7 @@ case_statement_list:
 	case_statement
 	{
 	   ast_case_statement_list *cases= new(state) ast_case_statement_list();
-	   cases->set_location(yylloc);
+	   cases->set_location(yylloc, state);
 
 	   cases->cases.push_tail(& $1->link);
 	   $$ = cases;
@@ -1757,21 +1758,21 @@ iteration_statement:
 	   void *ctx = state;
 	   $$ = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_while,
 	   					    NULL, $3, NULL, $5);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| DO statement WHILE '(' expression ')' ';'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_do_while,
 						    NULL, $5, NULL, $2);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| FOR '(' for_init_statement for_rest_statement ')' statement_no_new_scope
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_for,
 						    $3, $4.cond, $4.rest, $6);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -1807,31 +1808,31 @@ jump_statement:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_continue, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| BREAK ';'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_break, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| RETURN ';'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| RETURN expression ';'
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, $2);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	| DISCARD ';' // Fragment shader only.
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_discard, NULL);
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	}
 	;
 
@@ -1846,7 +1847,7 @@ function_definition:
 	{
 	   void *ctx = state;
 	   $$ = new(ctx) ast_function_definition();
-	   $$->set_location(yylloc);
+	   $$->set_location(yylloc, ctx);
 	   $$->prototype = $1;
 	   $$->body = $2;
 
diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp
index 21c3c6e..9954952 100644
--- a/src/glsl/glsl_parser_extras.cpp
+++ b/src/glsl/glsl_parser_extras.cpp
@@ -141,11 +141,18 @@ _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
 {
    va_list ap;
 
+   char sbuf[12];
+   const char *source = locp->source;
+   if (!source) {
+      source = sbuf;
+      sprintf (sbuf, "%u", locp->source_id);
+   }
+
    state->error = true;
 
    assert(state->info_log != NULL);
-   ralloc_asprintf_append(&state->info_log, "%u:%u(%u): error: ",
-					    locp->source,
+   ralloc_asprintf_append(&state->info_log, "%s:%u(%u): error: ",
+					    source,
 					    locp->first_line,
 					    locp->first_column);
    va_start(ap, fmt);
@@ -161,9 +168,16 @@ _mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state,
 {
    va_list ap;
 
+   char sbuf[12];
+   const char *source = locp->source;
+   if (!source) {
+      source = sbuf;
+      sprintf (sbuf, "%u", locp->source_id);
+   }
+
    assert(state->info_log != NULL);
-   ralloc_asprintf_append(&state->info_log, "%u:%u(%u): warning: ",
-					    locp->source,
+   ralloc_asprintf_append(&state->info_log, "%s:%u(%u): warning: ",
+					    source,
 					    locp->first_line,
 					    locp->first_column);
    va_start(ap, fmt);
@@ -464,6 +478,7 @@ ast_node::print(void) const
 
 ast_node::ast_node(void)
 {
+   this->location.source_id = 0;
    this->location.source = 0;
    this->location.line = 0;
    this->location.column = 0;
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
index 55676f5..8c8ab8e 100644
--- a/src/glsl/glsl_parser_extras.h
+++ b/src/glsl/glsl_parser_extras.h
@@ -212,6 +212,10 @@ struct _mesa_glsl_parse_state {
    /** Shaders containing built-in functions that are used for linking. */
    struct gl_shader *builtins_to_link[16];
    unsigned num_builtins_to_link;
+
+   /** Source currently being parsed */
+   unsigned source_id;
+   char *source;
 };
 
 typedef struct YYLTYPE {
@@ -219,7 +223,8 @@ typedef struct YYLTYPE {
    int first_column;
    int last_line;
    int last_column;
-   unsigned source;
+   unsigned source_id;
+   char *source;
 } YYLTYPE;
 # define YYLTYPE_IS_DECLARED 1
 # define YYLTYPE_IS_TRIVIAL 1
@@ -232,6 +237,8 @@ do {								\
       (Current).first_column = YYRHSLOC(Rhs, 1).first_column;	\
       (Current).last_line    = YYRHSLOC(Rhs, N).last_line;	\
       (Current).last_column  = YYRHSLOC(Rhs, N).last_column;	\
+      (Current).source       = YYRHSLOC(Rhs, 1).source;		\
+      (Current).source_id    = YYRHSLOC(Rhs, 1).source_id;	\
    }								\
    else								\
    {								\
@@ -239,8 +246,9 @@ do {								\
 	 YYRHSLOC(Rhs, 0).last_line;				\
       (Current).first_column = (Current).last_column =		\
 	 YYRHSLOC(Rhs, 0).last_column;				\
+      (Current).source       = YYRHSLOC(Rhs, 0).source;		\
+      (Current).source_id    = YYRHSLOC(Rhs, 0).source_id;	\
    }								\
-   (Current).source = 0;					\
 } while (0)
 
 extern void _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
@@ -296,7 +304,9 @@ extern "C" {
 #endif
 
 extern int preprocess(void *ctx, const char **shader, char **info_log,
-                      const struct gl_extensions *extensions, int api);
+                      const struct gl_extensions *extensions, int api,
+		      const char *base_path,
+		      const char *(*get_string)(void *param, const char *), void *param);
 
 extern void _mesa_destroy_shader_compiler(void);
 extern void _mesa_destroy_shader_compiler_caches(void);
diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp
index d43bf1a..5a005a3 100644
--- a/src/glsl/main.cpp
+++ b/src/glsl/main.cpp
@@ -21,6 +21,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #include <getopt.h>
+#include <unistd.h>
 
 #include "ast.h"
 #include "glsl_parser_extras.h"
@@ -129,14 +130,17 @@ usage_fail(const char *name)
 
 
 void
-compile_shader(struct gl_context *ctx, struct gl_shader *shader)
+compile_shader(struct gl_context *ctx, struct gl_shader *shader,
+	       const char *base_path,
+	       const char *(*get_string)(void *param, const char *), void *param)
 {
    struct _mesa_glsl_parse_state *state =
       new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
 
    const char *source = shader->Source;
    state->error = preprocess(state, &source, &state->info_log,
-			     state->extensions, ctx->API) != 0;
+			     state->extensions, ctx->API,
+			     base_path, get_string, param) != 0;
 
    if (!state->error) {
       _mesa_glsl_lexer_ctor(state, source);
@@ -198,6 +202,14 @@ compile_shader(struct gl_context *ctx, struct gl_shader *shader)
    return;
 }
 
+static const char *
+get_string(void *ctx, const char *name)
+{
+   return load_text_file(ctx, name);
+}
+
+extern "C" char *glcpp_canonicalize_path(void *ctx, const char *base_path, const char *file_name);
+
 int
 main(int argc, char **argv)
 {
@@ -222,6 +234,8 @@ main(int argc, char **argv)
    assert(whole_program != NULL);
    whole_program->InfoLog = ralloc_strdup(whole_program, "");
 
+   char *cur_dir = get_current_dir_name();
+
    for (/* empty */; argc > optind; optind++) {
       whole_program->Shaders =
 	 reralloc(whole_program, whole_program->Shaders,
@@ -247,13 +261,15 @@ main(int argc, char **argv)
       else
 	 usage_fail(argv[0]);
 
+
       shader->Source = load_text_file(whole_program, argv[optind]);
       if (shader->Source == NULL) {
 	 printf("File \"%s\" does not exist.\n", argv[optind]);
 	 exit(EXIT_FAILURE);
       }
 
-      compile_shader(ctx, shader);
+      char *base_path = glcpp_canonicalize_path(whole_program, cur_dir, argv[optind]);
+      compile_shader(ctx, shader, base_path, get_string, whole_program);
 
       if (!shader->CompileStatus) {
 	 printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
@@ -262,6 +278,8 @@ main(int argc, char **argv)
       }
    }
 
+   free(cur_dir);
+
    if ((status == EXIT_SUCCESS) && do_link)  {
       link_shaders(ctx, whole_program);
       status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;
diff --git a/src/glsl/test_optpass.cpp b/src/glsl/test_optpass.cpp
index 6abafb5..e3c7e1c 100644
--- a/src/glsl/test_optpass.cpp
+++ b/src/glsl/test_optpass.cpp
@@ -219,7 +219,7 @@ int test_optpass(int argc, char **argv)
       shader->Source = input.c_str();
       const char *source = shader->Source;
       state->error = preprocess(state, &source, &state->info_log,
-                                state->extensions, ctx->API) != 0;
+                                state->extensions, ctx->API, 0, 0, 0) != 0;
 
       if (!state->error) {
          _mesa_glsl_lexer_ctor(state, source);
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 697313f..dd0e0e9 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -3322,7 +3322,7 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
    }
 
    state->error = preprocess(state, &source, &state->info_log,
-			     &ctx->Extensions, ctx->API);
+			     &ctx->Extensions, ctx->API, 0, 0, 0);
 
    if (ctx->Shader.Flags & GLSL_DUMP) {
       printf("GLSL source for %s shader %d:\n",
-- 
1.7.4



More information about the mesa-dev mailing list