generic compile_error/compile_warning functions in con.c, issuing end-of-non-void warning from within the ast now

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-11-26 16:12:40 +01:00
parent e6928c6b78
commit 8e1ce2ab5e
3 changed files with 119 additions and 83 deletions

141
ast.c
View file

@ -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;
}

35
con.c
View file

@ -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;
}

26
gmqcc.h
View file

@ -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 ==============================*/
/*===================================================================*/