Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Makefile.am | 1 + libs/vkd3d-shader/preproc.h | 9 ++++ libs/vkd3d-shader/preproc.l | 24 ++++++++-- libs/vkd3d-shader/preproc.y | 60 +++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl_d3d12.c | 2 +- 6 files changed, 92 insertions(+), 5 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 514f0506..bf1d7bfa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -243,6 +243,7 @@ XFAIL_TESTS = \ tests/hlsl-vector-indexing.shader_test \ tests/hlsl-vector-indexing-uniform.shader_test \ tests/math.shader_test \ + tests/preproc-if.shader_test \ tests/preproc-ifdef.shader_test \ tests/preproc-if-expr.shader_test \ tests/preproc-invalid.shader_test \ diff --git a/libs/vkd3d-shader/preproc.h b/libs/vkd3d-shader/preproc.h index effcd995..1cb3d5d7 100644 --- a/libs/vkd3d-shader/preproc.h +++ b/libs/vkd3d-shader/preproc.h @@ -23,6 +23,12 @@
#include "vkd3d_shader_private.h"
+struct preproc_macro +{ + struct list entry; + char *name; +}; + struct preproc_if_state { /* Are we currently in a "true" block? */ @@ -41,6 +47,8 @@ struct preproc_ctx struct vkd3d_string_buffer buffer; struct vkd3d_shader_location location;
+ struct list macros; + struct preproc_if_state *if_stack; size_t if_count, if_stack_size;
@@ -52,6 +60,7 @@ struct preproc_ctx bool error; };
+void preproc_free_macro(struct preproc_macro *macro) DECLSPEC_HIDDEN; void preproc_warning(struct preproc_ctx *ctx, const struct vkd3d_shader_location *loc, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(4, 5) DECLSPEC_HIDDEN;
diff --git a/libs/vkd3d-shader/preproc.l b/libs/vkd3d-shader/preproc.l index 47ad1f13..2484e107 100644 --- a/libs/vkd3d-shader/preproc.l +++ b/libs/vkd3d-shader/preproc.l @@ -67,7 +67,7 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* <C_COMMENT,CXX_COMMENT><<EOF>> {yy_pop_state(yyscanner);} <C_COMMENT,CXX_COMMENT>. {}
-<INITIAL>{IDENTIFIER} {return T_TEXT;} +<INITIAL>{IDENTIFIER} {return T_IDENTIFIER;}
/* We have no use for floats, but shouldn't parse them as integers. */
@@ -100,6 +100,8 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* for (p = yytext + 1; strchr(" \t", *p); ++p) ;
+ if (!strcmp(p, "define")) + return T_DEFINE; if (!strcmp(p, "elif")) return T_ELIF; if (!strcmp(p, "else")) @@ -154,6 +156,7 @@ static int return_token(int token, YYSTYPE *lval, const char *text) { switch (token) { + case T_IDENTIFIER: case T_INTEGER: case T_TEXT: if (!(lval->string = vkd3d_strdup(text))) @@ -191,6 +194,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) { switch (token) { + case T_DEFINE: case T_ELIF: case T_ELSE: case T_ENDIF: @@ -208,8 +212,18 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) TRACE("Parsing token %d, line %d, in directive %d, string %s.\n", token, lloc->line, ctx->current_directive, debugstr_a(text));
- if (!ctx->current_directive && !preproc_is_writing(ctx)) - continue; + switch (ctx->current_directive) + { + case T_ELIF: + case T_ELSE: + case T_ENDIF: + case T_IF: + break; + + default: + if (!preproc_is_writing(ctx)) + continue; + }
if (ctx->current_directive) return return_token(token, lval, text); @@ -221,11 +235,13 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) { + struct preproc_macro *macro, *next; struct preproc_ctx ctx = {0}; YY_BUFFER_STATE top_buffer; void *output_code;
vkd3d_string_buffer_init(&ctx.buffer); + list_init(&ctx.macros); ctx.message_context = message_context; ctx.location.source_name = compile_info->source_name; ctx.location.line = 1; @@ -248,6 +264,8 @@ int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, }
vkd3d_free(ctx.if_stack); + LIST_FOR_EACH_ENTRY_SAFE(macro, next, &ctx.macros, struct preproc_macro, entry) + preproc_free_macro(macro);
if (ctx.error) { diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index 647bb45d..e608c5d8 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -66,6 +66,44 @@ static void yyerror(const YYLTYPE *loc, void *scanner, struct preproc_ctx *ctx, preproc_error(ctx, loc, VKD3D_SHADER_ERROR_PP_INVALID_SYNTAX, "%s", string); }
+static struct preproc_macro *preproc_find_macro(struct preproc_ctx *ctx, const char *name) +{ + struct preproc_macro *macro; + + LIST_FOR_EACH_ENTRY(macro, &ctx->macros, struct preproc_macro, entry) + { + if (!strcmp(macro->name, name)) + return macro; + } + return NULL; +} + +static bool preproc_add_macro(struct preproc_ctx *ctx, const struct vkd3d_shader_location *loc, char *name) +{ + struct preproc_macro *macro; + + if ((macro = preproc_find_macro(ctx, name))) + { + preproc_warning(ctx, loc, VKD3D_SHADER_WARNING_PP_ALREADY_DEFINED, "Redefinition of %s.", name); + preproc_free_macro(macro); + } + + TRACE("Defining new macro %s.\n", debugstr_a(name)); + + if (!(macro = vkd3d_malloc(sizeof(*macro)))) + return false; + macro->name = name; + list_add_tail(&ctx->macros, ¯o->entry); + return true; +} + +void preproc_free_macro(struct preproc_macro *macro) +{ + list_remove(¯o->entry); + vkd3d_free(macro->name); + vkd3d_free(macro); +} + static bool preproc_was_writing(struct preproc_ctx *ctx) { if (ctx->if_count < 2) @@ -135,17 +173,20 @@ static uint32_t preproc_parse_integer(const char *s) uint32_t integer; }
+%token <string> T_IDENTIFIER %token <string> T_INTEGER %token <string> T_TEXT
%token T_NEWLINE
+%token T_DEFINE "#define" %token T_ELIF "#elif" %token T_ELSE "#else" %token T_ENDIF "#endif" %token T_IF "#if"
%type <integer> expr +%type <string> body_token
%%
@@ -156,8 +197,25 @@ shader_text vkd3d_string_buffer_printf(&ctx->buffer, "\n"); }
+body_text + : %empty + | body_text body_token + { + vkd3d_free($2); + } + +body_token + : T_IDENTIFIER + | T_INTEGER + | T_TEXT + directive - : T_IF expr T_NEWLINE + : T_DEFINE T_IDENTIFIER body_text T_NEWLINE + { + if (!preproc_add_macro(ctx, &@$, $2)) + YYABORT; + } + | T_IF expr T_NEWLINE { if (!preproc_push_if(ctx, !!$2)) YYABORT; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index b89d20e2..1011be27 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -82,6 +82,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_PP_INVALID_SYNTAX = 4000,
+ VKD3D_SHADER_WARNING_PP_ALREADY_DEFINED = 4300, VKD3D_SHADER_WARNING_PP_INVALID_DIRECTIVE = 4301, VKD3D_SHADER_WARNING_PP_UNKNOWN_DIRECTIVE = 4303, VKD3D_SHADER_WARNING_PP_UNTERMINATED_IF = 4305, diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c index 77a7ea1a..38c1ab2c 100644 --- a/tests/hlsl_d3d12.c +++ b/tests/hlsl_d3d12.c @@ -349,7 +349,7 @@ static void test_preprocess(void)
for (i = 0; i < ARRAY_SIZE(tests); ++i) { - if (i == 43) + if (i == 6) continue; vkd3d_test_set_context("Source "%s"", tests[i].source); todo_if (i <= 4 || (i >= 9 && i <= 14))
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/preproc.l | 4 ++++ libs/vkd3d-shader/preproc.y | 6 ++++++ 2 files changed, 10 insertions(+)
diff --git a/libs/vkd3d-shader/preproc.l b/libs/vkd3d-shader/preproc.l index 2484e107..b79e5f97 100644 --- a/libs/vkd3d-shader/preproc.l +++ b/libs/vkd3d-shader/preproc.l @@ -110,6 +110,8 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* return T_ENDIF; if (!strcmp(p, "if")) return T_IF; + if (!strcmp(p, "ifdef")) + return T_IFDEF;
preproc_warning(ctx, yyget_lloc(yyscanner), VKD3D_SHADER_WARNING_PP_UNKNOWN_DIRECTIVE, "Ignoring unknown directive "%s".", yytext); @@ -199,6 +201,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case T_ELSE: case T_ENDIF: case T_IF: + case T_IFDEF: ctx->current_directive = token; break;
@@ -218,6 +221,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case T_ELSE: case T_ENDIF: case T_IF: + case T_IFDEF: break;
default: diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index e608c5d8..c66c0b9d 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -184,6 +184,7 @@ static uint32_t preproc_parse_integer(const char *s) %token T_ELSE "#else" %token T_ENDIF "#endif" %token T_IF "#if" +%token T_IFDEF "#ifdef"
%type <integer> expr %type <string> body_token @@ -220,6 +221,11 @@ directive if (!preproc_push_if(ctx, !!$2)) YYABORT; } + | T_IFDEF T_IDENTIFIER T_NEWLINE + { + preproc_push_if(ctx, !!preproc_find_macro(ctx, $2)); + vkd3d_free($2); + } | T_ELIF expr T_NEWLINE { if (ctx->if_count)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/preproc.l | 4 ++++ libs/vkd3d-shader/preproc.y | 6 ++++++ tests/hlsl_d3d12.c | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/preproc.l b/libs/vkd3d-shader/preproc.l index b79e5f97..f0e0b63d 100644 --- a/libs/vkd3d-shader/preproc.l +++ b/libs/vkd3d-shader/preproc.l @@ -112,6 +112,8 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* return T_IF; if (!strcmp(p, "ifdef")) return T_IFDEF; + if (!strcmp(p, "ifndef")) + return T_IFNDEF;
preproc_warning(ctx, yyget_lloc(yyscanner), VKD3D_SHADER_WARNING_PP_UNKNOWN_DIRECTIVE, "Ignoring unknown directive "%s".", yytext); @@ -202,6 +204,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case T_ENDIF: case T_IF: case T_IFDEF: + case T_IFNDEF: ctx->current_directive = token; break;
@@ -222,6 +225,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case T_ENDIF: case T_IF: case T_IFDEF: + case T_IFNDEF: break;
default: diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index c66c0b9d..b1d0c0f0 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -185,6 +185,7 @@ static uint32_t preproc_parse_integer(const char *s) %token T_ENDIF "#endif" %token T_IF "#if" %token T_IFDEF "#ifdef" +%token T_IFNDEF "#ifndef"
%type <integer> expr %type <string> body_token @@ -226,6 +227,11 @@ directive preproc_push_if(ctx, !!preproc_find_macro(ctx, $2)); vkd3d_free($2); } + | T_IFNDEF T_IDENTIFIER T_NEWLINE + { + preproc_push_if(ctx, !preproc_find_macro(ctx, $2)); + vkd3d_free($2); + } | T_ELIF expr T_NEWLINE { if (ctx->if_count) diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c index 38c1ab2c..8b8c3023 100644 --- a/tests/hlsl_d3d12.c +++ b/tests/hlsl_d3d12.c @@ -349,7 +349,7 @@ static void test_preprocess(void)
for (i = 0; i < ARRAY_SIZE(tests); ++i) { - if (i == 6) + if (i == 6 || i == 10 || i == 11) continue; vkd3d_test_set_context("Source "%s"", tests[i].source); todo_if (i <= 4 || (i >= 9 && i <= 14))
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/preproc.h | 44 +++++-- libs/vkd3d-shader/preproc.l | 129 +++++++++++++++---- libs/vkd3d-shader/preproc.y | 155 +++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl_d3d12.c | 16 +-- 5 files changed, 292 insertions(+), 53 deletions(-)
diff --git a/libs/vkd3d-shader/preproc.h b/libs/vkd3d-shader/preproc.h index 1cb3d5d7..87706d01 100644 --- a/libs/vkd3d-shader/preproc.h +++ b/libs/vkd3d-shader/preproc.h @@ -23,12 +23,6 @@
#include "vkd3d_shader_private.h"
-struct preproc_macro -{ - struct list entry; - char *name; -}; - struct preproc_if_state { /* Are we currently in a "true" block? */ @@ -39,18 +33,40 @@ struct preproc_if_state bool seen_else; };
+struct preproc_buffer +{ + void *lexer_buffer; + struct vkd3d_shader_location location; +}; + +struct preproc_file +{ + struct preproc_buffer buffer; + struct vkd3d_shader_code code; + char *filename; + + struct preproc_if_state *if_stack; + size_t if_count, if_stack_size; +}; + +struct preproc_macro +{ + struct list entry; + char *name; +}; + struct preproc_ctx { + const struct vkd3d_shader_preprocess_info *preprocess_info; void *scanner;
struct vkd3d_shader_message_context *message_context; struct vkd3d_string_buffer buffer; - struct vkd3d_shader_location location;
- struct list macros; + struct preproc_file *file_stack; + size_t file_count, file_stack_size;
- struct preproc_if_state *if_stack; - size_t if_count, if_stack_size; + struct list macros;
int current_directive;
@@ -60,8 +76,16 @@ struct preproc_ctx bool error; };
+void preproc_close_include(struct preproc_ctx *ctx, const struct vkd3d_shader_code *code) DECLSPEC_HIDDEN; void preproc_free_macro(struct preproc_macro *macro) DECLSPEC_HIDDEN; +bool preproc_push_include(struct preproc_ctx *ctx, char *filename, const struct vkd3d_shader_code *code) DECLSPEC_HIDDEN; void preproc_warning(struct preproc_ctx *ctx, const struct vkd3d_shader_location *loc, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(4, 5) DECLSPEC_HIDDEN;
+static struct preproc_file *preproc_get_top_file(struct preproc_ctx *ctx) +{ + assert(ctx->file_count); + return &ctx->file_stack[ctx->file_count - 1]; +} + #endif diff --git a/libs/vkd3d-shader/preproc.l b/libs/vkd3d-shader/preproc.l index f0e0b63d..958f4994 100644 --- a/libs/vkd3d-shader/preproc.l +++ b/libs/vkd3d-shader/preproc.l @@ -50,6 +50,8 @@ static void update_location(struct preproc_ctx *ctx); %s C_COMMENT %s CXX_COMMENT
+%s INCLUDE + NEWLINE \r?\n WS [ \t] IDENTIFIER [A-Za-z_][A-Za-z0-9_]* @@ -61,6 +63,7 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* <CXX_COMMENT>\{NEWLINE} {} <CXX_COMMENT>\n { yy_pop_state(yyscanner); + BEGIN(INITIAL); return T_NEWLINE; } <C_COMMENT>"*/" {yy_pop_state(yyscanner);} @@ -87,6 +90,9 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* <INITIAL>">>"=? {return T_TEXT;} <INITIAL>[-+*/%&|^=><!]= {return T_TEXT;}
+<INCLUDE>"[^"]*" {return T_STRING;} +<INCLUDE><[^>]*> {return T_STRING;} + /* C strings (including escaped quotes). */ <INITIAL>"([^"\]|\.)*" {return T_TEXT;}
@@ -100,6 +106,12 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* for (p = yytext + 1; strchr(" \t", *p); ++p) ;
+ if (!strcmp(p, "include")) + { + BEGIN(INCLUDE); + return T_INCLUDE; + } + if (!strcmp(p, "define")) return T_DEFINE; if (!strcmp(p, "elif")) @@ -120,8 +132,11 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* return T_TEXT; }
-<INITIAL>\{NEWLINE} {} -<INITIAL>{NEWLINE} {return T_NEWLINE;} +<INITIAL,INCLUDE>\{NEWLINE} {} +<INITIAL,INCLUDE>{NEWLINE} { + BEGIN(INITIAL); + return T_NEWLINE; + }
<INITIAL>{WS}+ {} <INITIAL>. {return T_TEXT;} @@ -132,28 +147,61 @@ static void update_location(struct preproc_ctx *ctx) { unsigned int i, leng = yyget_leng(ctx->scanner); const char *text = yyget_text(ctx->scanner); + struct preproc_buffer *buffer; + + buffer = &ctx->file_stack[ctx->file_count - 1].buffer;
/* We want to do this here, rather than before calling yylex(), because * some tokens are skipped by the lexer. */
- *yyget_lloc(ctx->scanner) = ctx->location; + *yyget_lloc(ctx->scanner) = buffer->location;
for (i = 0; i < leng; ++i) { - ++ctx->location.column; + ++buffer->location.column; if (text[i] == '\n') { - ctx->location.column = 1; - ++ctx->location.line; + buffer->location.column = 1; + ++buffer->location.line; } } }
+static void preproc_pop_buffer(struct preproc_ctx *ctx) +{ + struct preproc_file *file = &ctx->file_stack[ctx->file_count - 1]; + + assert(ctx->file_count); + + if (ctx->file_count > 1) + preproc_close_include(ctx, &file->code); + + if (file->if_count) + { + const struct vkd3d_shader_location loc = {.source_name = file->filename}; + + preproc_warning(ctx, &loc, VKD3D_SHADER_WARNING_PP_UNTERMINATED_IF, "Unterminated #if block."); + } + vkd3d_free(file->if_stack); + + vkd3d_free(file->filename); + + yy_delete_buffer(file->buffer.lexer_buffer, ctx->scanner); + + --ctx->file_count; + TRACE("File stack size is now %zu.\n", ctx->file_count); + + if (ctx->file_count) + yy_switch_to_buffer(ctx->file_stack[ctx->file_count - 1].buffer.lexer_buffer, ctx->scanner); +} + static bool preproc_is_writing(struct preproc_ctx *ctx) { - if (!ctx->if_count) + const struct preproc_file *file = preproc_get_top_file(ctx); + + if (!file->if_count) return true; - return ctx->if_stack[ctx->if_count - 1].current_true; + return file->if_stack[file->if_count - 1].current_true; }
static int return_token(int token, YYSTYPE *lval, const char *text) @@ -162,6 +210,7 @@ static int return_token(int token, YYSTYPE *lval, const char *text) { case T_IDENTIFIER: case T_INTEGER: + case T_STRING: case T_TEXT: if (!(lval->string = vkd3d_strdup(text))) return 0; @@ -181,8 +230,14 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) int token;
if (ctx->last_was_eof) - return 0; + { + preproc_pop_buffer(ctx); + if (!ctx->file_count) + return 0; + } + ctx->last_was_eof = false;
+ assert(ctx->file_count); if (!(token = preproc_lexer_lex(lval, lloc, scanner))) { ctx->last_was_eof = true; @@ -205,6 +260,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case T_IF: case T_IFDEF: case T_IFNDEF: + case T_INCLUDE: ctx->current_directive = token; break;
@@ -240,40 +296,65 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) } }
+bool preproc_push_include(struct preproc_ctx *ctx, char *filename, const struct vkd3d_shader_code *code) +{ + struct preproc_file *file; + + if (!vkd3d_array_reserve((void **)&ctx->file_stack, &ctx->file_stack_size, + ctx->file_count + 1, sizeof(*ctx->file_stack))) + return false; + file = &ctx->file_stack[ctx->file_count++]; + memset(file, 0, sizeof(*file)); + file->code = *code; + file->filename = filename; + file->buffer.lexer_buffer = yy_scan_bytes(code->code, code->size, ctx->scanner); + file->buffer.location.source_name = file->filename; + file->buffer.location.line = 1; + file->buffer.location.column = 1; + TRACE("File stack size is now %zu.\n", ctx->file_count); + ctx->last_was_newline = true; + return true; +} + int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) { + static const struct vkd3d_shader_preprocess_info default_preprocess_info = {0}; struct preproc_macro *macro, *next; struct preproc_ctx ctx = {0}; - YY_BUFFER_STATE top_buffer; + char *source_name; void *output_code;
vkd3d_string_buffer_init(&ctx.buffer); list_init(&ctx.macros); + if (!(ctx.preprocess_info = vkd3d_find_struct(compile_info->next, PREPROCESS_INFO))) + ctx.preprocess_info = &default_preprocess_info; ctx.message_context = message_context; - ctx.location.source_name = compile_info->source_name; - ctx.location.line = 1; - ctx.location.column = 1; + + if (!(source_name = vkd3d_strdup(compile_info->source_name ? compile_info->source_name : "<anonymous>"))) + { + vkd3d_string_buffer_cleanup(&ctx.buffer); + return VKD3D_ERROR_OUT_OF_MEMORY; + }
yylex_init_extra(&ctx, &ctx.scanner); - top_buffer = yy_scan_bytes(compile_info->source.code, compile_info->source.size, ctx.scanner); - ctx.last_was_newline = true; + if (!preproc_push_include(&ctx, source_name, &compile_info->source)) + { + yylex_destroy(ctx.scanner); + vkd3d_free(source_name); + vkd3d_string_buffer_cleanup(&ctx.buffer); + return VKD3D_ERROR_OUT_OF_MEMORY; + }
preproc_yyparse(ctx.scanner, &ctx);
- yy_delete_buffer(top_buffer, ctx.scanner); + while (ctx.file_count) + preproc_pop_buffer(&ctx); yylex_destroy(ctx.scanner);
- if (ctx.if_count) - { - const struct vkd3d_shader_location loc = {.source_name = ctx.location.source_name}; - - preproc_warning(&ctx, &loc, VKD3D_SHADER_WARNING_PP_UNTERMINATED_IF, "Unterminated #if block."); - } - - vkd3d_free(ctx.if_stack); LIST_FOR_EACH_ENTRY_SAFE(macro, next, &ctx.macros, struct preproc_macro, entry) preproc_free_macro(macro); + vkd3d_free(ctx.file_stack);
if (ctx.error) { diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index b1d0c0f0..7c12eb5c 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -23,6 +23,8 @@
#include "vkd3d_shader_private.h" #include "preproc.h" +#include <stdio.h> +#include <sys/stat.h>
#define PREPROC_YYLTYPE struct vkd3d_shader_location
@@ -106,18 +108,24 @@ void preproc_free_macro(struct preproc_macro *macro)
static bool preproc_was_writing(struct preproc_ctx *ctx) { - if (ctx->if_count < 2) + const struct preproc_file *file = preproc_get_top_file(ctx); + + /* This applies across files, since we can't #include anyway if we weren't + * writing. */ + if (file->if_count < 2) return true; - return ctx->if_stack[ctx->if_count - 2].current_true; + return file->if_stack[file->if_count - 2].current_true; }
static bool preproc_push_if(struct preproc_ctx *ctx, bool condition) { + struct preproc_file *file = preproc_get_top_file(ctx); struct preproc_if_state *state;
- if (!vkd3d_array_reserve((void **)&ctx->if_stack, &ctx->if_stack_size, ctx->if_count + 1, sizeof(*ctx->if_stack))) + if (!vkd3d_array_reserve((void **)&file->if_stack, &file->if_stack_size, + file->if_count + 1, sizeof(*file->if_stack))) return false; - state = &ctx->if_stack[ctx->if_count++]; + state = &file->if_stack[file->if_count++]; state->current_true = condition && preproc_was_writing(ctx); state->seen_true = condition; state->seen_else = false; @@ -156,6 +164,93 @@ static uint32_t preproc_parse_integer(const char *s) return ret; }
+static int default_open_include(const char *filename, bool local, + const char *parent_data, void *context, struct vkd3d_shader_code *out) +{ + uint8_t *data, *new_data; + size_t size = 4096; + struct stat st; + size_t pos = 0; + size_t ret; + FILE *f; + + if (!(f = fopen(filename, "rb"))) + { + ERR("Unable to open %s for reading.\n", debugstr_a(filename)); + return VKD3D_ERROR; + } + + if (fstat(fileno(f), &st) == -1) + { + ERR("Could not stat file %s.\n", debugstr_a(filename)); + fclose(f); + return VKD3D_ERROR; + } + + if (S_ISREG(st.st_mode)) + size = st.st_size; + + if (!(data = vkd3d_malloc(size))) + { + fclose(f); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (;;) + { + if (pos >= size) + { + if (size > SIZE_MAX / 2 || !(new_data = vkd3d_realloc(data, size * 2))) + { + vkd3d_free(data); + fclose(f); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + data = new_data; + size *= 2; + } + + if (!(ret = fread(&data[pos], 1, size - pos, f))) + break; + pos += ret; + } + + if (!feof(f)) + { + vkd3d_free(data); + return VKD3D_ERROR; + } + + fclose(f); + + out->code = data; + out->size = pos; + + return VKD3D_OK; +} + +static void default_close_include(const struct vkd3d_shader_code *code, void *context) +{ + vkd3d_free((void *)code->code); +} + +void preproc_close_include(struct preproc_ctx *ctx, const struct vkd3d_shader_code *code) +{ + PFN_vkd3d_shader_close_include close_include = ctx->preprocess_info->pfn_close_include; + + if (!close_include) + close_include = default_close_include; + + close_include(code, ctx->preprocess_info->include_context); +} + +static const void *get_parent_data(struct preproc_ctx *ctx) +{ + if (ctx->file_count == 1) + return NULL; + return preproc_get_top_file(ctx)->code.code; +} + }
%define api.prefix {preproc_yy} @@ -175,6 +270,7 @@ static uint32_t preproc_parse_integer(const char *s)
%token <string> T_IDENTIFIER %token <string> T_INTEGER +%token <string> T_STRING %token <string> T_TEXT
%token T_NEWLINE @@ -186,6 +282,7 @@ static uint32_t preproc_parse_integer(const char *s) %token T_IF "#if" %token T_IFDEF "#ifdef" %token T_IFNDEF "#ifndef" +%token T_INCLUDE "#include"
%type <integer> expr %type <string> body_token @@ -234,9 +331,11 @@ directive } | T_ELIF expr T_NEWLINE { - if (ctx->if_count) + const struct preproc_file *file = preproc_get_top_file(ctx); + + if (file->if_count) { - struct preproc_if_state *state = &ctx->if_stack[ctx->if_count - 1]; + struct preproc_if_state *state = &file->if_stack[file->if_count - 1];
if (state->seen_else) { @@ -256,9 +355,11 @@ directive } | T_ELSE T_NEWLINE { - if (ctx->if_count) + const struct preproc_file *file = preproc_get_top_file(ctx); + + if (file->if_count) { - struct preproc_if_state *state = &ctx->if_stack[ctx->if_count - 1]; + struct preproc_if_state *state = &file->if_stack[file->if_count - 1];
if (state->seen_else) { @@ -278,12 +379,46 @@ directive } | T_ENDIF T_NEWLINE { - if (ctx->if_count) - --ctx->if_count; + struct preproc_file *file = preproc_get_top_file(ctx); + + if (file->if_count) + --file->if_count; else preproc_warning(ctx, &@$, VKD3D_SHADER_WARNING_PP_INVALID_DIRECTIVE, "Ignoring #endif without prior #if."); } + | T_INCLUDE T_STRING T_NEWLINE + { + PFN_vkd3d_shader_open_include open_include = ctx->preprocess_info->pfn_open_include; + struct vkd3d_shader_code code; + char *filename; + int result; + + if (!(filename = vkd3d_malloc(strlen($2) - 1))) + YYABORT; + + if (!open_include) + open_include = default_open_include; + + memcpy(filename, $2 + 1, strlen($2) - 2); + filename[strlen($2) - 2] = 0; + + if (!(result = open_include(filename, $2[0] == '"', get_parent_data(ctx), + ctx->preprocess_info->include_context, &code))) + { + if (!preproc_push_include(ctx, filename, &code)) + { + preproc_close_include(ctx, &code); + vkd3d_free(filename); + } + } + else + { + preproc_error(ctx, &@$, VKD3D_SHADER_ERROR_PP_INCLUDE_FAILED, "Failed to open %s.", $2); + vkd3d_free(filename); + } + vkd3d_free($2); + }
expr : T_INTEGER diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 1011be27..5224c929 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -81,6 +81,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_RS_MIXED_DESCRIPTOR_RANGE_TYPES = 3004,
VKD3D_SHADER_ERROR_PP_INVALID_SYNTAX = 4000, + VKD3D_SHADER_ERROR_PP_INCLUDE_FAILED = 4002,
VKD3D_SHADER_WARNING_PP_ALREADY_DEFINED = 4300, VKD3D_SHADER_WARNING_PP_INVALID_DIRECTIVE = 4301, diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c index 8b8c3023..54ab94de 100644 --- a/tests/hlsl_d3d12.c +++ b/tests/hlsl_d3d12.c @@ -408,19 +408,17 @@ static void test_preprocess(void) todo ok(include_count_file2 == 2, "file2 was included %u times.\n", include_count_file2);
/* Macro invocation spread across multiple files. */ - todo check_preprocess(test_include2_top, NULL, &test_include, "pass", NULL); + if (0) + todo check_preprocess(test_include2_top, NULL, &test_include, "pass", NULL);
blob = errors = (ID3D10Blob *)0xdeadbeef; hr = D3DPreprocess(test_include_top, strlen(test_include_top), NULL, NULL, &test_include_fail, &blob, &errors); - todo ok(hr == E_FAIL, "Got hr %#x.\n", hr); - todo ok(blob == (ID3D10Blob *)0xdeadbeef, "Expected no compiled shader blob.\n"); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + ok(blob == (ID3D10Blob *)0xdeadbeef, "Expected no compiled shader blob.\n"); ok(!!errors, "Expected non-NULL error blob.\n"); - if (errors) - { - if (vkd3d_test_state.debug_level) - trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors)); - ID3D10Blob_Release(errors); - } + if (vkd3d_test_state.debug_level) + trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors)); + ID3D10Blob_Release(errors); }
START_TEST(hlsl_d3d12)
On Tue, Jan 5, 2021 at 5:18 PM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/preproc.h | 44 +++++-- libs/vkd3d-shader/preproc.l | 129 +++++++++++++++---- libs/vkd3d-shader/preproc.y | 155 +++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl_d3d12.c | 16 +-- 5 files changed, 292 insertions(+), 53 deletions(-)
@@ -60,8 +76,16 @@ struct preproc_ctx bool error; };
+void preproc_close_include(struct preproc_ctx *ctx, const struct vkd3d_shader_code *code) DECLSPEC_HIDDEN; void preproc_free_macro(struct preproc_macro *macro) DECLSPEC_HIDDEN; +bool preproc_push_include(struct preproc_ctx *ctx, char *filename, const struct vkd3d_shader_code *code) DECLSPEC_HIDDEN; void preproc_warning(struct preproc_ctx *ctx, const struct vkd3d_shader_location *loc, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(4, 5) DECLSPEC_HIDDEN;
+static struct preproc_file *preproc_get_top_file(struct preproc_ctx *ctx) +{
- assert(ctx->file_count);
- return &ctx->file_stack[ctx->file_count - 1];
+}
There are a couple of places in preproc.l (e.g. in update_location(), preproc_pop_buffer()) where this helper can be used, in particular one with the same assert too. It's a stylistic choice so not using it is also fine. You probably want to make the function inline though.
I like the patch overall.
On 1/7/21 6:49 AM, Matteo Bruni wrote:
On Tue, Jan 5, 2021 at 5:18 PM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/preproc.h | 44 +++++-- libs/vkd3d-shader/preproc.l | 129 +++++++++++++++---- libs/vkd3d-shader/preproc.y | 155 +++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl_d3d12.c | 16 +-- 5 files changed, 292 insertions(+), 53 deletions(-)
@@ -60,8 +76,16 @@ struct preproc_ctx bool error; };
+void preproc_close_include(struct preproc_ctx *ctx, const struct vkd3d_shader_code *code) DECLSPEC_HIDDEN; void preproc_free_macro(struct preproc_macro *macro) DECLSPEC_HIDDEN; +bool preproc_push_include(struct preproc_ctx *ctx, char *filename, const struct vkd3d_shader_code *code) DECLSPEC_HIDDEN; void preproc_warning(struct preproc_ctx *ctx, const struct vkd3d_shader_location *loc, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(4, 5) DECLSPEC_HIDDEN;
+static struct preproc_file *preproc_get_top_file(struct preproc_ctx *ctx) +{
- assert(ctx->file_count);
- return &ctx->file_stack[ctx->file_count - 1];
+}
There are a couple of places in preproc.l (e.g. in update_location(), preproc_pop_buffer()) where this helper can be used, in particular one with the same assert too. It's a stylistic choice so not using it is also fine. You probably want to make the function inline though.
I like the patch overall.
That sounds right. I think it ended up not being used there in the first place because of some restructuring of how I handled the buffer stack. I'll add those and resend.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/preproc.l | 3 +++ libs/vkd3d-shader/preproc.y | 12 ++++++++++++ 2 files changed, 15 insertions(+)
diff --git a/libs/vkd3d-shader/preproc.l b/libs/vkd3d-shader/preproc.l index 958f4994..2654ad62 100644 --- a/libs/vkd3d-shader/preproc.l +++ b/libs/vkd3d-shader/preproc.l @@ -126,6 +126,8 @@ IDENTIFIER [A-Za-z_][A-Za-z0-9_]* return T_IFDEF; if (!strcmp(p, "ifndef")) return T_IFNDEF; + if (!strcmp(p, "undef")) + return T_UNDEF;
preproc_warning(ctx, yyget_lloc(yyscanner), VKD3D_SHADER_WARNING_PP_UNKNOWN_DIRECTIVE, "Ignoring unknown directive "%s".", yytext); @@ -261,6 +263,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case T_IFDEF: case T_IFNDEF: case T_INCLUDE: + case T_UNDEF: ctx->current_directive = token; break;
diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index 7c12eb5c..49ba80b4 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -283,6 +283,7 @@ static const void *get_parent_data(struct preproc_ctx *ctx) %token T_IFDEF "#ifdef" %token T_IFNDEF "#ifndef" %token T_INCLUDE "#include" +%token T_UNDEF "#undef"
%type <integer> expr %type <string> body_token @@ -314,6 +315,17 @@ directive if (!preproc_add_macro(ctx, &@$, $2)) YYABORT; } + | T_UNDEF T_IDENTIFIER T_NEWLINE + { + struct preproc_macro *macro; + + if ((macro = preproc_find_macro(ctx, $2))) + { + TRACE("Removing macro definition %s.\n", debugstr_a($2)); + preproc_free_macro(macro); + } + vkd3d_free($2); + } | T_IF expr T_NEWLINE { if (!preproc_push_if(ctx, !!$2))
On Tue, 5 Jan 2021 at 17:17, Zebediah Figura zfigura@codeweavers.com wrote:
@@ -41,6 +47,8 @@ struct preproc_ctx struct vkd3d_string_buffer buffer; struct vkd3d_shader_location location;
- struct list macros;
Does that need to be a list? For the purposes of this series, it seems an array would work at least as well.
On 1/5/21 11:12 AM, Henri Verbeet wrote:
On Tue, 5 Jan 2021 at 17:17, Zebediah Figura zfigura@codeweavers.com wrote:
@@ -41,6 +47,8 @@ struct preproc_ctx struct vkd3d_string_buffer buffer; struct vkd3d_shader_location location;
- struct list macros;
Does that need to be a list? For the purposes of this series, it seems an array would work at least as well.
It eases removal via #undef. There's also a couple places that store pointers to the macro (I think they're not in this series, but rather relate to expansion) which would complicate using a flat array at least.
On Tue, 5 Jan 2021 at 18:22, Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
On 1/5/21 11:12 AM, Henri Verbeet wrote:
On Tue, 5 Jan 2021 at 17:17, Zebediah Figura zfigura@codeweavers.com wrote:
@@ -41,6 +47,8 @@ struct preproc_ctx struct vkd3d_string_buffer buffer; struct vkd3d_shader_location location;
- struct list macros;
Does that need to be a list? For the purposes of this series, it seems an array would work at least as well.
It eases removal via #undef. There's also a couple places that store pointers to the macro (I think they're not in this series, but rather relate to expansion) which would complicate using a flat array at least.
Unless we care about the order, removal would essentially be "macros[idx] = macros[--macro_count];" Storing pointers to macros would indeed be an issue, although I'd expect that to be an issue regardless of how macros are stored, unless you also e.g. reference count them. Either way, if it's needed for later patches that's fine.
On 1/5/21 12:02 PM, Henri Verbeet wrote:
On Tue, 5 Jan 2021 at 18:22, Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
On 1/5/21 11:12 AM, Henri Verbeet wrote:
On Tue, 5 Jan 2021 at 17:17, Zebediah Figura zfigura@codeweavers.com wrote:
@@ -41,6 +47,8 @@ struct preproc_ctx struct vkd3d_string_buffer buffer; struct vkd3d_shader_location location;
- struct list macros;
Does that need to be a list? For the purposes of this series, it seems an array would work at least as well.
It eases removal via #undef. There's also a couple places that store pointers to the macro (I think they're not in this series, but rather relate to expansion) which would complicate using a flat array at least.
Unless we care about the order, removal would essentially be "macros[idx] = macros[--macro_count];"
True; I forgot about that.
Storing pointers to macros would indeed be an issue, although I'd expect that to be an issue regardless of how macros are stored, unless you also e.g. reference count them. Either way, if it's needed for later patches that's fine.
That is true. Of course, using an array makes it worse, because now you're potentially affecting macros other than the one that's being deleted while expanded.
Incidentally, the following shader:
#define FUNC(a,b) a ## b FUNC(a, #undef FUNC b)
yields, with native d3dcompiler_47, the output "FUNC" and an error "not enough actual parameters for macro 'FUNC'".
I don't think it'd be very hard to fix up the code to make sure a macro in use can't be moved, but on the other hand it strikes me as unnecessarily fragile (wrt later reading or modification).
I also don't know how much of a performance concern this actually is.
On Tue, 5 Jan 2021 at 19:17, Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
Incidentally, the following shader:
#define FUNC(a,b) a ## b FUNC(a, #undef FUNC b)
yields, with native d3dcompiler_47, the output "FUNC" and an error "not enough actual parameters for macro 'FUNC'".
I don't think it'd be very hard to fix up the code to make sure a macro in use can't be moved, but on the other hand it strikes me as unnecessarily fragile (wrt later reading or modification).
I also don't know how much of a performance concern this actually is.
Unless the shader in question is a particularly enthusiastic user of the preprocessor, I wouldn't expect much of a practical performance impact at all. This is more of an instance of "linked-lists need justification".
On 1/5/21 1:06 PM, Henri Verbeet wrote:
On Tue, 5 Jan 2021 at 19:17, Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
Incidentally, the following shader:
#define FUNC(a,b) a ## b FUNC(a, #undef FUNC b)
yields, with native d3dcompiler_47, the output "FUNC" and an error "not enough actual parameters for macro 'FUNC'".
I don't think it'd be very hard to fix up the code to make sure a macro in use can't be moved, but on the other hand it strikes me as unnecessarily fragile (wrt later reading or modification).
I also don't know how much of a performance concern this actually is.
Unless the shader in question is a particularly enthusiastic user of the preprocessor, I wouldn't expect much of a practical performance impact at all. This is more of an instance of "linked-lists need justification".
Sure. I don't want to argue I've provided a lot of justification, of course, but it does make things a bit easier. I'd be just as comfortable with replacing the linked list with a list of pointers, if that's clearly preferable.
On Tue, 5 Jan 2021 at 22:42, Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
Sure. I don't want to argue I've provided a lot of justification, of course, but it does make things a bit easier. I'd be just as comfortable with replacing the linked list with a list of pointers, if that's clearly preferable.
I think the linked list is fine if later patches store pointers to the macros, in case that wasn't clear.
On Tue, Jan 5, 2021 at 5:17 PM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 1 + libs/vkd3d-shader/preproc.h | 9 ++++ libs/vkd3d-shader/preproc.l | 24 ++++++++-- libs/vkd3d-shader/preproc.y | 60 +++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl_d3d12.c | 2 +- 6 files changed, 92 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/preproc.h b/libs/vkd3d-shader/preproc.h index effcd995..1cb3d5d7 100644 --- a/libs/vkd3d-shader/preproc.h +++ b/libs/vkd3d-shader/preproc.h @@ -23,6 +23,12 @@
#include "vkd3d_shader_private.h"
+struct preproc_macro +{
- struct list entry;
- char *name;
+};
struct preproc_if_state { /* Are we currently in a "true" block? */ @@ -41,6 +47,8 @@ struct preproc_ctx struct vkd3d_string_buffer buffer; struct vkd3d_shader_location location;
- struct list macros;
- struct preproc_if_state *if_stack; size_t if_count, if_stack_size;
diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index 647bb45d..e608c5d8 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -66,6 +66,44 @@ static void yyerror(const YYLTYPE *loc, void *scanner, struct preproc_ctx *ctx, preproc_error(ctx, loc, VKD3D_SHADER_ERROR_PP_INVALID_SYNTAX, "%s", string); }
+static struct preproc_macro *preproc_find_macro(struct preproc_ctx *ctx, const char *name) +{
- struct preproc_macro *macro;
- LIST_FOR_EACH_ENTRY(macro, &ctx->macros, struct preproc_macro, entry)
- {
if (!strcmp(macro->name, name))
return macro;
- }
- return NULL;
+}
+static bool preproc_add_macro(struct preproc_ctx *ctx, const struct vkd3d_shader_location *loc, char *name) +{
- struct preproc_macro *macro;
- if ((macro = preproc_find_macro(ctx, name)))
- {
preproc_warning(ctx, loc, VKD3D_SHADER_WARNING_PP_ALREADY_DEFINED, "Redefinition of %s.", name);
preproc_free_macro(macro);
- }
- TRACE("Defining new macro %s.\n", debugstr_a(name));
- if (!(macro = vkd3d_malloc(sizeof(*macro))))
return false;
- macro->name = name;
- list_add_tail(&ctx->macros, ¯o->entry);
- return true;
+}
Not a big deal right now that defines are only looked up when searching for duplicates, and possibly neither in the future, but I'm a bit uncomfortable with using an unsorted list for defines. Maybe HLSL shaders in the wild are generally low on #define usage, but it seems to me that it isn't much more complicated to use e.g. an rbtree instead (to name another data structure which is readily available in vkd3d) and I can't think of other obvious downsides to taking care of this right away.
On 1/7/21 4:31 AM, Matteo Bruni wrote:
On Tue, Jan 5, 2021 at 5:17 PM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 1 + libs/vkd3d-shader/preproc.h | 9 ++++ libs/vkd3d-shader/preproc.l | 24 ++++++++-- libs/vkd3d-shader/preproc.y | 60 +++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl_d3d12.c | 2 +- 6 files changed, 92 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/preproc.h b/libs/vkd3d-shader/preproc.h index effcd995..1cb3d5d7 100644 --- a/libs/vkd3d-shader/preproc.h +++ b/libs/vkd3d-shader/preproc.h @@ -23,6 +23,12 @@
#include "vkd3d_shader_private.h"
+struct preproc_macro +{
- struct list entry;
- char *name;
+};
struct preproc_if_state { /* Are we currently in a "true" block? */ @@ -41,6 +47,8 @@ struct preproc_ctx struct vkd3d_string_buffer buffer; struct vkd3d_shader_location location;
- struct list macros;
- struct preproc_if_state *if_stack; size_t if_count, if_stack_size;
diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index 647bb45d..e608c5d8 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -66,6 +66,44 @@ static void yyerror(const YYLTYPE *loc, void *scanner, struct preproc_ctx *ctx, preproc_error(ctx, loc, VKD3D_SHADER_ERROR_PP_INVALID_SYNTAX, "%s", string); }
+static struct preproc_macro *preproc_find_macro(struct preproc_ctx *ctx, const char *name) +{
- struct preproc_macro *macro;
- LIST_FOR_EACH_ENTRY(macro, &ctx->macros, struct preproc_macro, entry)
- {
if (!strcmp(macro->name, name))
return macro;
- }
- return NULL;
+}
+static bool preproc_add_macro(struct preproc_ctx *ctx, const struct vkd3d_shader_location *loc, char *name) +{
- struct preproc_macro *macro;
- if ((macro = preproc_find_macro(ctx, name)))
- {
preproc_warning(ctx, loc, VKD3D_SHADER_WARNING_PP_ALREADY_DEFINED, "Redefinition of %s.", name);
preproc_free_macro(macro);
- }
- TRACE("Defining new macro %s.\n", debugstr_a(name));
- if (!(macro = vkd3d_malloc(sizeof(*macro))))
return false;
- macro->name = name;
- list_add_tail(&ctx->macros, ¯o->entry);
- return true;
+}
Not a big deal right now that defines are only looked up when searching for duplicates, and possibly neither in the future, but I'm a bit uncomfortable with using an unsorted list for defines. Maybe HLSL shaders in the wild are generally low on #define usage, but it seems to me that it isn't much more complicated to use e.g. an rbtree instead (to name another data structure which is readily available in vkd3d) and I can't think of other obvious downsides to taking care of this right away.
Sure, I think that's reasonable. I'll switch this to an rbtree.