diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 14817aaf1..2286f8bb0 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -594,6 +594,7 @@ typedef struct { int verbosity; // 0=silent, goes up to 2 currently qboolean save_temps; // save temporary files qboolean files_dat; // generate files.dat + qboolean traditional; // behave more like qcc } options_t; extern options_t options; diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index c92bfa658..efbcb47cd 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -192,7 +192,10 @@ emit_assign_expr (int oper, expr_t *e) warning (e1, "assignment to constant %s (Moooooooo!)", def_a->name); } else { - error (e1, "assignment to constant %s", def_a->name); + if (options.traditional) + warning (e1, "assignment to constant %s", def_a->name); + else + error (e1, "assignment to constant %s", def_a->name); } } def_b = emit_sub_expr (e2, def_a); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 0140339b6..8d6d303d4 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1449,7 +1449,9 @@ function_expr (expr_t *e1, expr_t *e2) if (parm_count > ftype->num_parms) { return error (e1, "too many arguments"); } else if (parm_count < ftype->num_parms) { - return error (e1, "too few arguments"); + if (!options.traditional) + return error (e1, "too few arguments"); + warning (e1, "too few arguments"); } } for (i = parm_count, e = e2; i > 0; i--, e = e->next) { @@ -1524,9 +1526,18 @@ expr_t * return_expr (function_t *f, expr_t *e) { if (!e) { - if (f->def->type->aux_type != &type_void) - return error (e, "return from non-void function without a value"); - } else { + if (f->def->type->aux_type != &type_void) { + if (options.traditional) { + warning (e, "return from non-void function without a value"); + e = new_expr (); + e->type = ex_nil; + } else { + e = error (e, "return from non-void function without a value"); + return e; + } + } + } + if (e) { type_t *t = get_type (e); if (f->def->type->aux_type == &type_void) @@ -1737,10 +1748,14 @@ assign_expr (expr_t *e1, expr_t *e2) convert_nil (e2, t2); } - if (t1 != t2) - return type_mismatch (e1, e2, op); - else + if (t1 != t2) { + if (!options.traditional || t1->type != ev_func || t2->type != ev_func) + return type_mismatch (e1, e2, op); + warning (e1, "assignment between disparate function types"); type = t1; + } else { + type = t1; + } if (is_indirect (e1) && is_indirect (e2)) { expr_t *temp = new_temp_def_expr (t1); diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index ceb1bc123..730cd7dcd 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -216,34 +216,35 @@ typedef struct { const char *name; int value; type_t *type; + int traditional; int version; } keyword_t; static keyword_t keywords[] = { - {"void", TYPE, &type_void, PROG_ID_VERSION}, - {"float", TYPE, &type_float, PROG_ID_VERSION}, - {"string", TYPE, &type_string, PROG_ID_VERSION}, - {"vector", TYPE, &type_vector, PROG_ID_VERSION}, - {"entity", TYPE, &type_entity, PROG_ID_VERSION}, - {"quaternion", TYPE, &type_quaternion, PROG_VERSION}, - {"integer", TYPE, &type_integer, PROG_VERSION}, - {"function", TYPE, &type_function, PROG_VERSION}, - {"local", LOCAL, 0, PROG_ID_VERSION}, - {"return", RETURN, 0, PROG_ID_VERSION}, - {"while", WHILE, 0, PROG_ID_VERSION}, - {"do", DO, 0, PROG_ID_VERSION}, - {"if", IF, 0, PROG_ID_VERSION}, - {"else", ELSE, 0, PROG_ID_VERSION}, - {"for", FOR, 0, PROG_ID_VERSION}, - {"break", BREAK, 0, PROG_ID_VERSION}, - {"continue", CONTINUE, 0, PROG_ID_VERSION}, - {"switch", SWITCH, 0, PROG_ID_VERSION}, - {"case", CASE, 0, PROG_ID_VERSION}, - {"default", DEFAULT, 0, PROG_ID_VERSION}, - {"NIL", NIL, 0, PROG_ID_VERSION}, - {"struct", STRUCT, 0, PROG_VERSION}, - {"enum", ENUM, 0, PROG_ID_VERSION}, - {"typedef", TYPEDEF, 0, PROG_ID_VERSION}, + {"void", TYPE, &type_void, 1, PROG_ID_VERSION}, + {"float", TYPE, &type_float, 1, PROG_ID_VERSION}, + {"string", TYPE, &type_string, 1, PROG_ID_VERSION}, + {"vector", TYPE, &type_vector, 1, PROG_ID_VERSION}, + {"entity", TYPE, &type_entity, 1, PROG_ID_VERSION}, + {"quaternion", TYPE, &type_quaternion, 0, PROG_VERSION}, + {"integer", TYPE, &type_integer, 0, PROG_VERSION}, + {"function", TYPE, &type_function, 0, PROG_VERSION}, + {"local", LOCAL, 0, 1, PROG_ID_VERSION}, + {"return", RETURN, 0, 1, PROG_ID_VERSION}, + {"while", WHILE, 0, 1, PROG_ID_VERSION}, + {"do", DO, 0, 1, PROG_ID_VERSION}, + {"if", IF, 0, 1, PROG_ID_VERSION}, + {"else", ELSE, 0, 1, PROG_ID_VERSION}, + {"for", FOR, 0, 0, PROG_ID_VERSION}, + {"break", BREAK, 0, 0, PROG_ID_VERSION}, + {"continue", CONTINUE, 0, 0, PROG_ID_VERSION}, + {"switch", SWITCH, 0, 0, PROG_ID_VERSION}, + {"case", CASE, 0, 0, PROG_ID_VERSION}, + {"default", DEFAULT, 0, 0, PROG_ID_VERSION}, + {"NIL", NIL, 0, 0, PROG_ID_VERSION}, + {"struct", STRUCT, 0, 0, PROG_VERSION}, + {"enum", ENUM, 0, 0, PROG_ID_VERSION}, + {"typedef", TYPEDEF, 0, 0, PROG_ID_VERSION}, }; static const char * @@ -263,7 +264,8 @@ type_or_name (char *token) int i; keyword_tab = Hash_NewTable (1021, keyword_get_key, 0, 0); for (i = 0; i < sizeof (keywords) / sizeof (keywords[0]); i++) - if (keywords[i].version <= options.code.progsversion) + if (keywords[i].traditional >= options.traditional + && keywords[i].version <= options.code.progsversion) Hash_Add (keyword_tab, &keywords[i]); } keyword = Hash_Find (keyword_tab, token); diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index fb11b2a8f..47513d27b 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -80,6 +80,7 @@ static struct option const long_options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"files", no_argument, 0, 'F'}, + {"traditional", no_argument, 0, 't'}, #ifdef USE_CPP {"define", required_argument, 0, 'D'}, {"include", required_argument, 0, 'I'}, @@ -857,6 +858,10 @@ DecodeArgs (int argc, char **argv) case 'g': // debug options.code.debug = true; break; + case 't': // traditional + options.traditional = true; + options.code.progsversion = PROG_ID_VERSION; + break; case 'C':{ // code options char *opts = strdup (optarg); char *temp = strtok (opts, ",");