diff --git a/libs/vkd3d-shader/preproc.h b/libs/vkd3d-shader/preproc.h index 3848cf1b..d653976a 100644 --- a/libs/vkd3d-shader/preproc.h +++ b/libs/vkd3d-shader/preproc.h @@ -60,6 +60,7 @@ struct preproc_expansion { struct preproc_buffer buffer; const struct preproc_text *text; + struct preproc_text *arg_values; /* Back-pointer to the macro, if this expansion a macro body. This is * necessary so that argument tokens can be correctly replaced. */ struct preproc_macro *macro; @@ -72,7 +73,6 @@ struct preproc_macro char **arg_names; size_t arg_count; - struct preproc_text *arg_values; struct preproc_text body; }; @@ -117,6 +117,7 @@ struct preproc_ctx STATE_ARGS, } state; unsigned int paren_depth; + struct preproc_text *arg_values; } text_func, directive_func; int current_directive; diff --git a/libs/vkd3d-shader/preproc.l b/libs/vkd3d-shader/preproc.l index d2fae3f6..4a8d0fdd 100644 --- a/libs/vkd3d-shader/preproc.l +++ b/libs/vkd3d-shader/preproc.l @@ -29,11 +29,11 @@ #define YY_DECL static int preproc_lexer_lex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner) -static struct preproc_macro *preproc_get_top_macro(struct preproc_ctx *ctx) +static struct preproc_expansion *preproc_get_top_expansion(struct preproc_ctx *ctx) { if (!ctx->expansion_count) return NULL; - return ctx->expansion_stack[ctx->expansion_count - 1].macro; + return &ctx->expansion_stack[ctx->expansion_count - 1]; } static void update_location(struct preproc_ctx *ctx); @@ -132,14 +132,14 @@ INT_SUFFIX [uUlL]{0,2} if (!ctx->last_was_newline) { - struct preproc_macro *macro; + struct preproc_expansion *exp; /* Stringification is only done for function-like macro bodies. * Anywhere else, we need to parse it as two separate tokens. * We could use a state for this, but yyless() is easier and cheap. */ - if ((macro = preproc_get_top_macro(ctx)) && macro->arg_count) + if ((exp = preproc_get_top_expansion(ctx)) && exp->macro && exp->macro->arg_count) return T_HASHSTRING; yyless(1); @@ -258,6 +258,12 @@ static void preproc_pop_buffer(struct preproc_ctx *ctx) yy_delete_buffer(exp->buffer.lexer_buffer, ctx->scanner); + if (exp->macro) + { + for (unsigned int i = 0; i < exp->macro->arg_count; ++i) + vkd3d_string_buffer_cleanup(&exp->arg_values[i].text); + free(exp->arg_values); + } --ctx->expansion_count; TRACE("Expansion stack size is now %zu.\n", ctx->expansion_count); } @@ -310,15 +316,15 @@ static int return_token(int token, YYSTYPE *lval, const char *text) static const struct preproc_text *find_arg_expansion(struct preproc_ctx *ctx, const char *s) { - struct preproc_macro *macro; + struct preproc_expansion *exp; unsigned int i; - if ((macro = preproc_get_top_macro(ctx))) + if ((exp = preproc_get_top_expansion(ctx)) && exp->macro) { - for (i = 0; i < macro->arg_count; ++i) + for (i = 0; i < exp->macro->arg_count; ++i) { - if (!strcmp(s, macro->arg_names[i])) - return ¯o->arg_values[i]; + if (!strcmp(s, exp->macro->arg_names[i])) + return &exp->arg_values[i]; } } return NULL; @@ -330,7 +336,7 @@ static void preproc_text_add(struct preproc_text *text, const char *string) } static bool preproc_push_expansion(struct preproc_ctx *ctx, - const struct preproc_text *text, struct preproc_macro *macro) + const struct preproc_text *text, struct preproc_macro *macro, struct preproc_text *arg_values) { struct preproc_expansion *exp; @@ -342,6 +348,7 @@ static bool preproc_push_expansion(struct preproc_ctx *ctx, exp->buffer.lexer_buffer = yy_scan_bytes(text->text.buffer, text->text.content_size, ctx->scanner); exp->buffer.location = text->location; exp->macro = macro; + exp->arg_values = arg_values; TRACE("Expansion stack size is now %zu.\n", ctx->expansion_count); return true; } @@ -542,7 +549,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) if ((expansion = find_arg_expansion(ctx, text))) { - preproc_push_expansion(ctx, expansion, NULL); + preproc_push_expansion(ctx, expansion, NULL, NULL); continue; } @@ -550,7 +557,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) { if (!macro->arg_count) { - preproc_push_expansion(ctx, ¯o->body, macro); + preproc_push_expansion(ctx, ¯o->body, macro, NULL); } else { @@ -616,16 +623,19 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case STATE_IDENTIFIER: if (token == '(') { - struct preproc_text *first_arg = &func_state->macro->arg_values[0]; - unsigned int i; + struct preproc_text *arg_values; + + if (!(arg_values = calloc(func_state->macro->arg_count, sizeof(*arg_values)))) + return 0; + + for (unsigned int i = 0; i < func_state->macro->arg_count; ++i) + vkd3d_string_buffer_init(&arg_values[i].text); + arg_values[0].location = *lloc; func_state->arg_count = 0; func_state->paren_depth = 1; func_state->state = STATE_ARGS; - for (i = 0; i < func_state->macro->arg_count; ++i) - func_state->macro->arg_values[i].text.content_size = 0; - - first_arg->location = *lloc; + func_state->arg_values = arg_values; } else { @@ -649,7 +659,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) VKD3D_ASSERT(func_state->macro->arg_count); if (func_state->arg_count < func_state->macro->arg_count) - current_arg = &func_state->macro->arg_values[func_state->arg_count]; + current_arg = &func_state->arg_values[func_state->arg_count]; switch (token) { @@ -664,7 +674,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) if ((expansion = find_arg_expansion(ctx, text))) { - preproc_push_expansion(ctx, expansion, NULL); + preproc_push_expansion(ctx, expansion, NULL, NULL); continue; } @@ -700,7 +710,8 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) { if (++func_state->arg_count == func_state->macro->arg_count) { - preproc_push_expansion(ctx, &func_state->macro->body, func_state->macro); + preproc_push_expansion(ctx, &func_state->macro->body, + func_state->macro, func_state->arg_values); } else { diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y index 366e351e..c6be17bd 100644 --- a/libs/vkd3d-shader/preproc.y +++ b/libs/vkd3d-shader/preproc.y @@ -91,7 +91,6 @@ bool preproc_add_macro(struct preproc_ctx *ctx, const struct vkd3d_shader_locati size_t arg_count, const struct vkd3d_shader_location *body_loc, struct vkd3d_string_buffer *body) { struct preproc_macro *macro; - unsigned int i; int ret; if ((macro = preproc_find_macro(ctx, name))) @@ -108,14 +107,6 @@ bool preproc_add_macro(struct preproc_ctx *ctx, const struct vkd3d_shader_locati macro->name = name; macro->arg_names = arg_names; macro->arg_count = arg_count; - macro->arg_values = NULL; - if (arg_count && !(macro->arg_values = vkd3d_calloc(arg_count, sizeof(*macro->arg_values)))) - { - vkd3d_free(macro); - return false; - } - for (i = 0; i < arg_count; ++i) - vkd3d_string_buffer_init(¯o->arg_values[i].text); macro->body.text = *body; macro->body.location = *body_loc; ret = rb_put(&ctx->macros, name, ¯o->entry); @@ -129,12 +120,8 @@ void preproc_free_macro(struct preproc_macro *macro) vkd3d_free(macro->name); for (i = 0; i < macro->arg_count; ++i) - { - vkd3d_string_buffer_cleanup(¯o->arg_values[i].text); vkd3d_free(macro->arg_names[i]); - } vkd3d_free(macro->arg_names); - vkd3d_free(macro->arg_values); vkd3d_string_buffer_cleanup(¯o->body.text); vkd3d_free(macro); } diff --git a/tests/preproc-macro.shader_test b/tests/preproc-macro.shader_test index 7cb768e0..911825df 100644 --- a/tests/preproc-macro.shader_test +++ b/tests/preproc-macro.shader_test @@ -375,3 +375,7 @@ key1 [preproc] #define key1 ::key2 pass key1 + +[preproc] +#define KEY(a, b) a b +KEY(KEY(x, y), pass)