#include "glcpp.h"
#include "main/mtypes.h"
+#include "util/strndup.h"
+
+const char *
+_mesa_lookup_shader_include(struct gl_context *ctx, char *path,
+ bool error_check);
static void
yyerror(YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
static void
glcpp_parser_lex_from(glcpp_parser_t *parser, token_list_t *list);
+struct define_include {
+ glcpp_parser_t *parser;
+ YYLTYPE *loc;
+};
+
+static void
+glcpp_parser_copy_defines(const void *key, void *data, void *closure);
+
static void
add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
/* We use HASH_TOKEN, DEFINE_TOKEN and VERSION_TOKEN (as opposed to
* HASH, DEFINE, and VERSION) to avoid conflicts with other symbols,
* (such as the <HASH> and <DEFINE> start conditions in the lexer). */
-%token DEFINED ELIF_EXPANDED HASH_TOKEN DEFINE_TOKEN FUNC_IDENTIFIER OBJ_IDENTIFIER ELIF ELSE ENDIF ERROR_TOKEN IF IFDEF IFNDEF LINE PRAGMA UNDEF VERSION_TOKEN GARBAGE IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE PLUS_PLUS MINUS_MINUS PATH
+%token DEFINED ELIF_EXPANDED HASH_TOKEN DEFINE_TOKEN FUNC_IDENTIFIER OBJ_IDENTIFIER ELIF ELSE ENDIF ERROR_TOKEN IF IFDEF IFNDEF LINE PRAGMA UNDEF VERSION_TOKEN GARBAGE IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE PLUS_PLUS MINUS_MINUS PATH INCLUDE
%token PASTE
%type <ival> INTEGER operator SPACE integer_constant version_constant
%type <expression_value> expression
-%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER ERROR_TOKEN PRAGMA PATH
+%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER ERROR_TOKEN PRAGMA PATH INCLUDE
%type <string_list> identifier_list
%type <token> preprocessing_token
%type <token_list> pp_tokens replacement_list text_line
_mesa_hash_table_remove (parser->defines, entry);
}
}
+| HASH_TOKEN INCLUDE NEWLINE {
+ /* Remove leading and trailing "" or <> */
+ char *start = strchr($2, '"');
+ if (!start)
+ start = strchr($2, '<');
+ char *path = strndup(start + 1, strlen(start + 1) - 1);
+
+ const char *shader =
+ _mesa_lookup_shader_include(parser->gl_ctx, path, false);
+ free(path);
+
+ if (!shader)
+ glcpp_error(&@1, parser, "%s not found", $2);
+ else {
+ /* Create a temporary parser with the same settings */
+ glcpp_parser_t *tmp_parser =
+ glcpp_parser_create(parser->gl_ctx, parser->extensions, parser->state);
+ tmp_parser->version_set = true;
+ tmp_parser->version = parser->version;
+
+ /* Set the shader source and run the lexer */
+ glcpp_lex_set_source_string(tmp_parser, shader);
+
+ /* Copy any existing define macros to the temporary
+ * shade include parser.
+ */
+ struct define_include di;
+ di.parser = tmp_parser;
+ di.loc = &@1;
+
+ hash_table_call_foreach(parser->defines,
+ glcpp_parser_copy_defines,
+ &di);
+
+ /* Parse the include string before adding to the
+ * preprocessor output.
+ */
+ glcpp_parser_parse(tmp_parser);
+ _mesa_string_buffer_printf(parser->info_log, "%s",
+ tmp_parser->info_log->buf);
+ _mesa_string_buffer_printf(parser->output, "%s",
+ tmp_parser->output->buf);
+
+ /* Copy any new define macros to the parent parser
+ * and steal the memory of our temp parser so we don't
+ * free these new defines before they are no longer
+ * needed.
+ */
+ di.parser = parser;
+ di.loc = &@1;
+ ralloc_steal(parser, tmp_parser);
+
+ hash_table_call_foreach(tmp_parser->defines,
+ glcpp_parser_copy_defines,
+ &di);
+
+ /* Destroy tmp parser memory we no longer need */
+ glcpp_lex_destroy(tmp_parser->scanner);
+ _mesa_hash_table_destroy(tmp_parser->defines, NULL);
+ }
+ }
| HASH_TOKEN IF pp_tokens NEWLINE {
/* Be careful to only evaluate the 'if' expression if
* we are not skipping. When we are skipping, we
INITIAL_PP_OUTPUT_BUF_SIZE);
parser->error = 0;
+ parser->gl_ctx = gl_ctx;
parser->extensions = extensions;
parser->extension_list = &gl_ctx->Extensions;
parser->state = state;
_glcpp_parser_handle_version_declaration(parser, language_version,
NULL, false);
}
+
+static void
+glcpp_parser_copy_defines(const void *key, void *data, void *closure)
+{
+ struct define_include *di = (struct define_include *) closure;
+ macro_t *macro = (macro_t *) data;
+
+ /* If we hit an error on a previous pass, just return */
+ if (di->parser->error)
+ return;
+
+ const char *identifier = macro->identifier;
+ struct hash_entry *entry = _mesa_hash_table_search(di->parser->defines,
+ identifier);
+
+ macro_t *previous = entry ? entry->data : NULL;
+ if (previous) {
+ if (_macro_equal(macro, previous)) {
+ return;
+ }
+ glcpp_error(di->loc, di->parser, "Redefinition of macro %s\n",
+ identifier);
+ }
+
+ _mesa_hash_table_insert(di->parser->defines, identifier, macro);
+}
--- /dev/null
+/*
+ * Copyright © 2019 Timothy Arceri
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* This file declares stripped-down versions of functions that
+ * normally exist outside of the glsl folder, so that they can be used
+ * when running the GLSL compiler standalone (for unit testing or
+ * compiling builtins).
+ */
+
+#include "pp_standalone_scaffolding.h"
+
+const char *
+_mesa_lookup_shader_include(struct gl_context *ctx, char *path,
+ bool error_check)
+{
+ (void) ctx;
+ (void) path;
+ (void) error_check;
+
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright © 2019 Timothy Arceri
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* This file declares stripped-down versions of functions that
+ * normally exist outside of the glcpp folder, so that they can be used
+ * when running the GLSL compiler standalone (for unit testing or
+ * compiling builtins).
+ */
+
+#ifndef PP_STANDALONE_SCAFFOLDING_H
+#define PP_STANDALONE_SCAFFOLDING_H
+
+#include <stddef.h>
+#include "main/mtypes.h"
+
+const char *
+_mesa_lookup_shader_include(struct gl_context *ctx, char *path,
+ bool error_check);
+
+#endif /* PP_STANDALONE_SCAFFOLDING_H */