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))