Implement --traditional so qfcc can be a nicer qcc. This disables several

keywords (quaternion integer function for break continue switch case default
NIL struct enum typedef) and converts some errors to warnings (assignment to
constants, insufficient function arguments, return; from non-void function,
anal function `pointer' type checks)
This commit is contained in:
Bill Currie 2002-02-18 06:23:59 +00:00
parent 7c9a19283b
commit d1fcfd1939
5 changed files with 59 additions and 33 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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, ",");