From 8e1ce2ab5e3d87aebd1adf72e339db259d690043 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Mon, 26 Nov 2012 16:12:40 +0100 Subject: [PATCH] generic compile_error/compile_warning functions in con.c, issuing end-of-non-void warning from within the ast now --- ast.c | 141 +++++++++++++++++++++++++++----------------------------- con.c | 35 ++++++++++++++ gmqcc.h | 26 +++++++---- 3 files changed, 119 insertions(+), 83 deletions(-) diff --git a/ast.c b/ast.c index a622db6..188dcec 100644 --- a/ast.c +++ b/ast.c @@ -36,15 +36,6 @@ ( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn -/* error handling */ -static void asterror(lex_ctx ctx, const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - con_cvprintmsg((void*)&ctx, LVL_ERROR, "error", msg, ap); - va_end(ap); -} - /* It must not be possible to get here. */ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) { @@ -474,7 +465,7 @@ ast_unary* ast_unary_new(lex_ctx ctx, int op, if (op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) { self->expression.vtype = TYPE_FLOAT; } else - asterror(ctx, "cannot determine type of unary operation %s", asm_instr[op].m); + compile_error(ctx, "cannot determine type of unary operation %s", asm_instr[op].m); return self; } @@ -510,7 +501,7 @@ void ast_return_delete(ast_return *self) ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field) { if (field->expression.vtype != TYPE_FIELD) { - asterror(ctx, "ast_entfield_new with expression not of type field"); + compile_error(ctx, "ast_entfield_new with expression not of type field"); return NULL; } return ast_entfield_new_force(ctx, entity, field, field->expression.next); @@ -559,7 +550,7 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel if (owner->expression.vtype != TYPE_VECTOR && owner->expression.vtype != TYPE_FIELD) { - asterror(ctx, "member-access on an invalid owner of type %s", type_name[owner->expression.vtype]); + compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->expression.vtype]); mem_d(self); return NULL; } @@ -626,7 +617,7 @@ ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_exp } if (array->expression.vtype == TYPE_FIELD && outtype->expression.vtype == TYPE_ARRAY) { if (self->expression.vtype != TYPE_ARRAY) { - asterror(ast_ctx(self), "array_index node on type"); + compile_error(ast_ctx(self), "array_index node on type"); ast_array_index_delete(self); return NULL; } @@ -899,7 +890,7 @@ bool ast_call_check_types(ast_call *self) char tgot[1024]; ast_type_to_string(self->params[i], tgot, sizeof(tgot)); ast_type_to_string((ast_expression*)func->expression.params[i], texp, sizeof(texp)); - asterror(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s", + compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s", (unsigned int)(i+1), texp, tgot); /* we don't immediately return */ retval = false; @@ -1006,7 +997,7 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) vtype->hasvalue || vtype->expression.vtype != TYPE_FUNCTION) { - asterror(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i", + compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i", (int)!vtype, (int)vtype->hasvalue, vtype->expression.vtype); @@ -1097,7 +1088,7 @@ bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_valu if (!self->ir_v) { char typename[1024]; ast_type_to_string((ast_expression*)self, typename, sizeof(typename)); - asterror(ast_ctx(self), "ast_value used before generated %s %s", typename, self->name); + compile_error(ast_ctx(self), "ast_value used before generated %s %s", typename, self->name); return false; } *out = self->ir_v; @@ -1126,7 +1117,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) ast_expression *fieldtype = self->expression.next; if (self->hasvalue) { - asterror(ast_ctx(self), "TODO: constant field pointers with value"); + compile_error(ast_ctx(self), "TODO: constant field pointers with value"); goto error; } @@ -1140,20 +1131,20 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) ast_value *array = (ast_value*)fieldtype; if (!ast_istype(fieldtype, ast_value)) { - asterror(ast_ctx(self), "internal error: ast_value required"); + compile_error(ast_ctx(self), "internal error: ast_value required"); return false; } /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */ if (!array->expression.count || array->expression.count > opts_max_array_size) - asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count); + compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count); elemtype = &array->expression.next->expression; vtype = elemtype->vtype; v = ir_builder_create_field(ir, self->name, vtype); if (!v) { - asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name); + compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name); return false; } if (vtype == TYPE_FIELD) @@ -1172,7 +1163,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) array->ir_values[ai] = ir_builder_create_field(ir, name, vtype); if (!array->ir_values[ai]) { mem_d(name); - asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name); + compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name); return false; } if (vtype == TYPE_FIELD) @@ -1202,11 +1193,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) /* same as with field arrays */ if (!self->expression.count || self->expression.count > opts_max_array_size) - asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count); + compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count); v = ir_builder_create_global(ir, self->name, vtype); if (!v) { - asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name); + compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name); return false; } if (vtype == TYPE_FIELD) @@ -1224,7 +1215,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) self->ir_values[ai] = ir_builder_create_global(ir, name, vtype); if (!self->ir_values[ai]) { mem_d(name); - asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", name); + compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", name); return false; } if (vtype == TYPE_FIELD) @@ -1240,7 +1231,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) */ v = ir_builder_create_global(ir, self->name, self->expression.vtype); if (!v) { - asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name); + compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name); return false; } if (self->expression.vtype == TYPE_FIELD) @@ -1264,16 +1255,16 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) goto error; break; case TYPE_ARRAY: - asterror(ast_ctx(self), "TODO: global constant array"); + compile_error(ast_ctx(self), "TODO: global constant array"); break; case TYPE_FUNCTION: - asterror(ast_ctx(self), "global of type function not properly generated"); + compile_error(ast_ctx(self), "global of type function not properly generated"); goto error; /* Cannot generate an IR value for a function, * need a pointer pointing to a function rather. */ default: - asterror(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype); + compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype); break; } } @@ -1307,24 +1298,24 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) int vtype = elemtype->vtype; if (param) { - asterror(ast_ctx(self), "array-parameters are not supported"); + compile_error(ast_ctx(self), "array-parameters are not supported"); return false; } /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */ if (!self->expression.count || self->expression.count > opts_max_array_size) { - asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count); + compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count); } self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count); if (!self->ir_values) { - asterror(ast_ctx(self), "failed to allocate array values"); + compile_error(ast_ctx(self), "failed to allocate array values"); return false; } v = ir_function_create_local(func, self->name, vtype, param); if (!v) { - asterror(ast_ctx(self), "ir_function_create_local failed"); + compile_error(ast_ctx(self), "ir_function_create_local failed"); return false; } if (vtype == TYPE_FIELD) @@ -1340,7 +1331,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) snprintf(name + namelen, 16, "[%u]", (unsigned int)ai); self->ir_values[ai] = ir_function_create_local(func, name, vtype, param); if (!self->ir_values[ai]) { - asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name); + compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name); return false; } if (vtype == TYPE_FIELD) @@ -1377,7 +1368,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) goto error; break; default: - asterror(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype); + compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype); break; } } @@ -1415,7 +1406,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) irf = self->ir_func; if (!irf) { - asterror(ast_ctx(self), "ast_function's related ast_value was not generated yet"); + compile_error(ast_ctx(self), "ast_function's related ast_value was not generated yet"); return false; } @@ -1436,13 +1427,13 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) } if (!vec_size(self->blocks)) { - asterror(ast_ctx(self), "function `%s` has no body", self->name); + compile_error(ast_ctx(self), "function `%s` has no body", self->name); return false; } self->curblock = ir_function_create_block(ast_ctx(self), irf, "entry"); if (!self->curblock) { - asterror(ast_ctx(self), "failed to allocate entry block for `%s`", self->name); + compile_error(ast_ctx(self), "failed to allocate entry block for `%s`", self->name); return false; } @@ -1457,7 +1448,6 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) { return ir_block_create_return(self->curblock, NULL); /* From now on the parser has to handle this situation */ -#if 0 if (!self->vtype->expression.next || self->vtype->expression.next->expression.vtype == TYPE_VOID) { @@ -1466,10 +1456,13 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) else { /* error("missing return"); */ - asterror(ast_ctx(self), "function `%s` missing return value", self->name); - return false; + if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES, + "control reaches end of non-void function (`%s`)", + self->name)) + { + return false; + } } -#endif } return true; } @@ -1489,7 +1482,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu * of the form: (a, b, c) = x should not assign to c... */ if (lvalue) { - asterror(ast_ctx(self), "not an l-value (code-block)"); + compile_error(ast_ctx(self), "not an l-value (code-block)"); return false; } @@ -1511,7 +1504,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu { if (!ast_local_codegen(self->locals[i], func->ir_func, false)) { if (opts_debug) - asterror(ast_ctx(self), "failed to generate local `%s`", self->locals[i]->name); + compile_error(ast_ctx(self), "failed to generate local `%s`", self->locals[i]->name); return false; } } @@ -1520,7 +1513,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu { ast_expression_codegen *gen = self->exprs[i]->expression.codegen; if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) { - asterror(ast_ctx(self->exprs[i]), "unreachable statement"); + compile_error(ast_ctx(self->exprs[i]), "unreachable statement"); return false; } if (!(*gen)(self->exprs[i], func, false, out)) @@ -1568,13 +1561,13 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu ir_instr *call; if (lvalue) { - asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues"); + compile_error(ast_ctx(self), "array-subscript assignment cannot produce lvalues"); return false; } arr = (ast_value*)ai->array; if (!ast_istype(ai->array, ast_value) || !arr->setter) { - asterror(ast_ctx(self), "value has no setter (%s)", arr->name); + compile_error(ast_ctx(self), "value has no setter (%s)", arr->name); return false; } @@ -1636,7 +1629,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va /* A binary operation cannot yield an l-value */ if (lvalue) { - asterror(ast_ctx(self), "not an l-value (binop)"); + compile_error(ast_ctx(self), "not an l-value (binop)"); return false; } @@ -1673,7 +1666,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va if (!OPTS_FLAG(PERL_LOGIC)) { notop = type_not_instr[left->vtype]; if (notop == AINSTR_END) { - asterror(ast_ctx(self), "don't know how to cast to bool..."); + compile_error(ast_ctx(self), "don't know how to cast to bool..."); return false; } left = ir_block_create_unary(func->curblock, @@ -1701,7 +1694,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va if (!OPTS_FLAG(PERL_LOGIC)) { notop = type_not_instr[right->vtype]; if (notop == AINSTR_END) { - asterror(ast_ctx(self), "don't know how to cast to bool..."); + compile_error(ast_ctx(self), "don't know how to cast to bool..."); return false; } right = ir_block_create_unary(func->curblock, @@ -1725,7 +1718,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va if (!OPTS_FLAG(PERL_LOGIC)) { notop = type_not_instr[(*out)->vtype]; if (notop == AINSTR_END) { - asterror(ast_ctx(self), "don't know how to cast to bool..."); + compile_error(ast_ctx(self), "don't know how to cast to bool..."); return false; } *out = ir_block_create_unary(func->curblock, @@ -1814,13 +1807,13 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i ir_instr *call; if (lvalue) { - asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues"); + compile_error(ast_ctx(self), "array-subscript assignment cannot produce lvalues"); return false; } arr = (ast_value*)ai->array; if (!ast_istype(ai->array, ast_value) || !arr->setter) { - asterror(ast_ctx(self), "value has no setter (%s)", arr->name); + compile_error(ast_ctx(self), "value has no setter (%s)", arr->name); return false; } @@ -1866,7 +1859,7 @@ bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_valu /* An unary operation cannot yield an l-value */ if (lvalue) { - asterror(ast_ctx(self), "not an l-value (binop)"); + compile_error(ast_ctx(self), "not an l-value (binop)"); return false; } @@ -1900,12 +1893,12 @@ bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_va * anything... */ if (lvalue) { - asterror(ast_ctx(self), "return-expression is not an l-value"); + compile_error(ast_ctx(self), "return-expression is not an l-value"); return false; } if (self->expression.outr) { - asterror(ast_ctx(self), "internal error: ast_return cannot be reused, it bears no result!"); + compile_error(ast_ctx(self), "internal error: ast_return cannot be reused, it bears no result!"); return false; } self->expression.outr = (ir_value*)1; @@ -1963,7 +1956,7 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i ent, field, self->expression.vtype); } if (!*out) { - asterror(ast_ctx(self), "failed to create %s instruction (output type %s)", + compile_error(ast_ctx(self), "failed to create %s instruction (output type %s)", (lvalue ? "ADDRESS" : "FIELD"), type_name[self->expression.vtype]); return false; @@ -2019,7 +2012,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva } if (!ast_istype(self->array, ast_value)) { - asterror(ast_ctx(self), "array indexing this way is not supported"); + compile_error(ast_ctx(self), "array indexing this way is not supported"); /* note this would actually be pointer indexing because the left side is * not an actual array but (hopefully) an indexable expression. * Once we get integer arithmetic, and GADDRESS/GSTORE/GLOAD instruction @@ -2038,12 +2031,12 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva ir_instr *call; if (lvalue) { - asterror(ast_ctx(self), "(.2) array indexing here needs a compile-time constant"); + compile_error(ast_ctx(self), "(.2) array indexing here needs a compile-time constant"); return false; } if (!arr->getter) { - asterror(ast_ctx(self), "value has no getter, don't know how to index it"); + compile_error(ast_ctx(self), "value has no getter, don't know how to index it"); return false; } @@ -2070,7 +2063,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva else if (idx->expression.vtype == TYPE_INTEGER) *out = arr->ir_values[idx->constval.vint]; else { - asterror(ast_ctx(self), "array indexing here needs an integer constant"); + compile_error(ast_ctx(self), "array indexing here needs an integer constant"); return false; } return true; @@ -2095,7 +2088,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va (void)lvalue; if (self->expression.outr) { - asterror(ast_ctx(self), "internal error: ast_ifthen cannot be reused, it bears no result!"); + compile_error(ast_ctx(self), "internal error: ast_ifthen cannot be reused, it bears no result!"); return false; } self->expression.outr = (ir_value*)1; @@ -2316,7 +2309,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value (void)out; if (self->expression.outr) { - asterror(ast_ctx(self), "internal error: ast_loop cannot be reused, it bears no result!"); + compile_error(ast_ctx(self), "internal error: ast_loop cannot be reused, it bears no result!"); return false; } self->expression.outr = (ir_value*)1; @@ -2521,12 +2514,12 @@ bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue, *out = NULL; if (lvalue) { - asterror(ast_ctx(self), "break/continue expression is not an l-value"); + compile_error(ast_ctx(self), "break/continue expression is not an l-value"); return false; } if (self->expression.outr) { - asterror(ast_ctx(self), "internal error: ast_breakcont cannot be reused!"); + compile_error(ast_ctx(self), "internal error: ast_breakcont cannot be reused!"); return false; } self->expression.outr = (ir_value*)1; @@ -2537,7 +2530,7 @@ bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue, target = func->breakblock; if (!target) { - asterror(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break")); + compile_error(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break")); return false; } @@ -2565,12 +2558,12 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va uint16_t cmpinstr; if (lvalue) { - asterror(ast_ctx(self), "switch expression is not an l-value"); + compile_error(ast_ctx(self), "switch expression is not an l-value"); return false; } if (self->expression.outr) { - asterror(ast_ctx(self), "internal error: ast_switch cannot be reused!"); + compile_error(ast_ctx(self), "internal error: ast_switch cannot be reused!"); return false; } self->expression.outr = (ir_value*)1; @@ -2588,7 +2581,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va cmpinstr = type_eq_instr[irop->vtype]; if (cmpinstr >= AINSTR_END) { ast_type_to_string(self->operand, typestr, sizeof(typestr)); - asterror(ast_ctx(self), "invalid type to perform a switch on: %s", typestr); + compile_error(ast_ctx(self), "invalid type to perform a switch on: %s", typestr); return false; } @@ -2707,14 +2700,14 @@ bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_valu *out = NULL; if (lvalue) { - asterror(ast_ctx(self), "internal error: ast_label cannot be an lvalue"); + compile_error(ast_ctx(self), "internal error: ast_label cannot be an lvalue"); return false; } /* simply create a new block and jump to it */ self->irblock = ir_function_create_block(ast_ctx(self), func->ir_func, self->name); if (!self->irblock) { - asterror(ast_ctx(self), "failed to allocate label block `%s`", self->name); + compile_error(ast_ctx(self), "failed to allocate label block `%s`", self->name); return false; } if (!func->curblock->final) { @@ -2738,7 +2731,7 @@ bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value { *out = NULL; if (lvalue) { - asterror(ast_ctx(self), "internal error: ast_goto cannot be an lvalue"); + compile_error(ast_ctx(self), "internal error: ast_goto cannot be an lvalue"); return false; } @@ -2747,14 +2740,14 @@ bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value /* we already tried once, this is the callback */ self->irblock_from->final = false; if (!ir_block_create_jump(self->irblock_from, self->target->irblock)) { - asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name); + compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name); return false; } } else { if (!ir_block_create_jump(func->curblock, self->target->irblock)) { - asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name); + compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name); return false; } } @@ -2783,7 +2776,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value /* return values are never lvalues */ if (lvalue) { - asterror(ast_ctx(self), "not an l-value (function call)"); + compile_error(ast_ctx(self), "not an l-value (function call)"); return false; } diff --git a/con.c b/con.c index 2bd8e39..c8c2634 100644 --- a/con.c +++ b/con.c @@ -360,3 +360,38 @@ void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, .. con_cvprintmsg(ctx, lvl, msgtype, msg, va); va_end (va); } + +/* General error interface */ +size_t compile_errors = 0; +size_t compile_warnings = 0; + +void compile_error(lex_ctx ctx, const char *msg, ...) +{ + va_list ap; + ++compile_errors; + va_start(ap, msg); + con_cvprintmsg((void*)&ctx, LVL_ERROR, "error", msg, ap); + va_end(ap); +} + +bool GMQCC_WARN compile_warning(lex_ctx ctx, int warntype, const char *fmt, ...) +{ + va_list ap; + int lvl = LVL_WARNING; + + if (!OPTS_WARN(warntype)) + return false; + + if (opts_werror) { + ++compile_errors; + lvl = LVL_ERROR; + } + else + ++compile_warnings; + + va_start(ap, fmt); + con_vprintmsg(lvl, ctx.file, ctx.line, "warning", fmt, ap); + va_end(ap); + + return opts_werror; +} diff --git a/gmqcc.h b/gmqcc.h index 7533bb4..44095a0 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -552,6 +552,16 @@ uint32_t code_genstring (const char *string); uint32_t code_cachedstring(const char *string); qcint code_alloc_field (size_t qcsize); +/* + * A shallow copy of a lex_file to remember where which ast node + * came from. + */ +typedef struct { + const char *file; + size_t line; +} lex_ctx; + + /*===================================================================*/ /*============================ con.c ================================*/ /*===================================================================*/ @@ -589,6 +599,13 @@ int con_vout (const char *fmt, va_list va); int con_err (const char *fmt, ...); int con_out (const char *fmt, ...); +/* error/warning interface */ +extern size_t compile_errors; +extern size_t compile_warnings; + +void compile_error(lex_ctx ctx, const char *msg, ...); +bool GMQCC_WARN compile_warning(lex_ctx ctx, int warntype, const char *fmt, ...); + /*===================================================================*/ /*========================= assembler.c =============================*/ /*===================================================================*/ @@ -687,15 +704,6 @@ vector vec3_sub (vector, vector); qcfloat vec3_mulvv(vector, vector); vector vec3_mulvf(vector, float); -/* - * A shallow copy of a lex_file to remember where which ast node - * came from. - */ -typedef struct { - const char *file; - size_t line; -} lex_ctx; - /*===================================================================*/ /*============================= exec.c ==============================*/ /*===================================================================*/ -- 2.39.2