From: Wolfgang Bumiller Date: Sat, 12 Jan 2013 12:01:20 +0000 (+0100) Subject: vararg accessor generation X-Git-Tag: before-library~295 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=6dfdf69a8e96ea2f5f5e6f89bbe8fd6262268846 vararg accessor generation --- diff --git a/ast.c b/ast.c index 2f8a2bc..0f5b05c 100644 --- a/ast.c +++ b/ast.c @@ -1074,6 +1074,8 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) vtype->hasvalue = true; vtype->constval.vfunc = self; + self->varargs = NULL; + return self; } @@ -1096,6 +1098,8 @@ void ast_function_delete(ast_function *self) vec_free(self->blocks); vec_free(self->breakblocks); vec_free(self->continueblocks); + if (self->varargs) + ast_delete(self->varargs); mem_d(self); } @@ -1405,7 +1409,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) func->flags |= IR_FLAG_HAS_ARRAYS; - if (param) { + if (param && !(self->expression.flags & AST_FLAG_IS_VARARG)) { compile_error(ast_ctx(self), "array-parameters are not supported"); return false; } @@ -1571,6 +1575,11 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) } } + if (self->varargs) { + if (!ast_local_codegen(self->varargs, self->ir_func, true)) + return false; + } + if (self->builtin) { irf->builtin = self->builtin; return true; diff --git a/ast.h b/ast.h index b2c4aed..463e6e4 100644 --- a/ast.h +++ b/ast.h @@ -150,7 +150,8 @@ typedef struct #define AST_FLAG_INITIALIZED (1<<3) #define AST_FLAG_DEPRECATED (1<<4) #define AST_FLAG_INCLUDE_DEF (1<<5) -#define AST_FLAG_VARARG_COUNT (1<<6) +#define AST_FLAG_IS_VARARG (1<<6) +#define AST_FLAG_VARARG_COUNT (1<<7) #define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN) /* Value @@ -644,6 +645,8 @@ struct ast_function_s char labelbuf[64]; ast_block* *blocks; + + ast_value *varargs; }; ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype); /* This will NOT delete the underlying ast_value */ diff --git a/parser.c b/parser.c index 6c9b2fd..e69faac 100644 --- a/parser.c +++ b/parser.c @@ -119,6 +119,8 @@ static bool parse_statement_or_block(parser_t *parser, ast_expression **out); static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases); static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels); +static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname); +static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname); static void parseerror(parser_t *parser, const char *fmt, ...) { @@ -210,12 +212,18 @@ static ast_value* parser_const_float(parser_t *parser, double d) { size_t i; ast_value *out; + lex_ctx ctx; for (i = 0; i < vec_size(parser->imm_float); ++i) { const double compare = parser->imm_float[i]->constval.vfloat; if (memcmp((const void*)&compare, (const void *)&d, sizeof(double)) == 0) return parser->imm_float[i]; } - out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_FLOAT); + if (parser->lex) + ctx = parser_ctx(parser); + else { + memset(&ctx, 0, sizeof(ctx)); + } + out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT); out->cvq = CV_CONST; out->hasvalue = true; out->constval.vfloat = d; @@ -3872,6 +3880,27 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } vec_push(parser->functions, func); + if (var->expression.flags & AST_FLAG_VARIADIC) { + char name[1024]; + ast_value *varargs = ast_value_new(ast_ctx(var), "reserved:va_args", TYPE_ARRAY); + varargs->expression.flags |= AST_FLAG_IS_VARARG; + varargs->expression.next = (ast_expression*)ast_value_new(ast_ctx(var), NULL, TYPE_VECTOR); + varargs->expression.count = 0; + snprintf(name, sizeof(name), "%s##va##SET", var->name); + if (!parser_create_array_setter_proto(parser, varargs, name)) { + ast_delete(varargs); + ast_block_delete(block); + goto enderr; + } + snprintf(name, sizeof(name), "%s##va##GET", var->name); + if (!parser_create_array_getter_proto(parser, varargs, varargs->expression.next, name)) { + ast_delete(varargs); + ast_block_delete(block); + goto enderr; + } + func->varargs = varargs; + } + parser->function = func; if (!parse_block_into(parser, block)) { ast_block_delete(block); @@ -4142,9 +4171,8 @@ static bool parser_create_array_accessor(parser_t *parser, ast_value *array, con return true; } -static bool parser_create_array_setter(parser_t *parser, ast_value *array, const char *funcname) +static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname) { - ast_expression *root = NULL; ast_value *index = NULL; ast_value *value = NULL; ast_function *func; @@ -4152,11 +4180,11 @@ static bool parser_create_array_setter(parser_t *parser, ast_value *array, const if (!ast_istype(array->expression.next, ast_value)) { parseerror(parser, "internal error: array accessor needs to build an ast_value with a copy of the element type"); - return false; + return NULL; } if (!parser_create_array_accessor(parser, array, funcname, &fval)) - return false; + return NULL; func = fval->constval.vfunc; fval->expression.next = (ast_expression*)ast_value_new(ast_ctx(array), "", TYPE_VOID); @@ -4171,21 +4199,39 @@ static bool parser_create_array_setter(parser_t *parser, ast_value *array, const vec_push(fval->expression.params, index); vec_push(fval->expression.params, value); - root = array_setter_node(parser, array, index, value, 0, array->expression.count); - if (!root) { - parseerror(parser, "failed to build accessor search tree"); - goto cleanup; - } - array->setter = fval; - return ast_block_add_expr(func->blocks[0], root); + return fval; cleanup: if (index) ast_delete(index); if (value) ast_delete(value); - if (root) ast_delete(root); ast_delete(func); ast_delete(fval); - return false; + return NULL; +} + +static bool parser_create_array_setter_impl(parser_t *parser, ast_value *array) +{ + ast_expression *root = NULL; + root = array_setter_node(parser, array, + array->setter->expression.params[0], + array->setter->expression.params[1], + 0, array->expression.count); + if (!root) { + parseerror(parser, "failed to build accessor search tree"); + return false; + } + if (!ast_block_add_expr(array->setter->constval.vfunc->blocks[0], root)) { + ast_delete(root); + return false; + } + return true; +} + +static bool parser_create_array_setter(parser_t *parser, ast_value *array, const char *funcname) +{ + if (!parser_create_array_setter_proto(parser, array, funcname)) + return false; + return parser_create_array_setter_impl(parser, array); } static bool parser_create_array_field_setter(parser_t *parser, ast_value *array, const char *funcname) @@ -4237,9 +4283,8 @@ cleanup: return false; } -static bool parser_create_array_getter(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname) +static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname) { - ast_expression *root = NULL; ast_value *index = NULL; ast_value *fval; ast_function *func; @@ -4249,11 +4294,11 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const */ if (!ast_istype(array->expression.next, ast_value)) { parseerror(parser, "internal error: array accessor needs to build an ast_value with a copy of the element type"); - return false; + return NULL; } if (!parser_create_array_accessor(parser, array, funcname, &fval)) - return false; + return NULL; func = fval->constval.vfunc; fval->expression.next = ast_type_copy(ast_ctx(array), elemtype); @@ -4265,20 +4310,36 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const } vec_push(fval->expression.params, index); - root = array_getter_node(parser, array, index, 0, array->expression.count); - if (!root) { - parseerror(parser, "failed to build accessor search tree"); - goto cleanup; - } - array->getter = fval; - return ast_block_add_expr(func->blocks[0], root); + return fval; cleanup: if (index) ast_delete(index); - if (root) ast_delete(root); ast_delete(func); ast_delete(fval); - return false; + return NULL; +} + +static bool parser_create_array_getter_impl(parser_t *parser, ast_value *array) +{ + ast_expression *root = NULL; + + root = array_getter_node(parser, array, array->getter->expression.params[0], 0, array->expression.count); + if (!root) { + parseerror(parser, "failed to build accessor search tree"); + return false; + } + if (!ast_block_add_expr(array->getter->constval.vfunc->blocks[0], root)) { + ast_delete(root); + return false; + } + return true; +} + +static bool parser_create_array_getter(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname) +{ + if (!parser_create_array_getter_proto(parser, array, elemtype, funcname)) + return false; + return parser_create_array_getter_impl(parser, array); } static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef); @@ -5737,8 +5798,27 @@ bool parser_finish(const char *output) } } for (i = 0; i < vec_size(parser->functions); ++i) { - if (!ast_function_codegen(parser->functions[i], ir)) { - con_out("failed to generate function %s\n", parser->functions[i]->name); + ast_function *f = parser->functions[i]; + if (f->varargs) { + if (parser->max_param_count > vec_size(f->vtype->expression.params)) { + f->varargs->expression.count = parser->max_param_count - vec_size(f->vtype->expression.params); + if (!parser_create_array_setter_impl(parser, f->varargs)) { + con_out("failed to generate vararg setter for %s\n", f->name); + ir_builder_delete(ir); + return false; + } + if (!parser_create_array_getter_impl(parser, f->varargs)) { + con_out("failed to generate vararg getter for %s\n", f->name); + ir_builder_delete(ir); + return false; + } + } else { + ast_delete(f->varargs); + f->varargs = NULL; + } + } + if (!ast_function_codegen(f, ir)) { + con_out("failed to generate function %s\n", f->name); ir_builder_delete(ir); return false; }