mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 20:41:20 +00:00
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:
parent
7c9a19283b
commit
d1fcfd1939
5 changed files with 59 additions and 33 deletions
|
@ -594,6 +594,7 @@ typedef struct {
|
||||||
int verbosity; // 0=silent, goes up to 2 currently
|
int verbosity; // 0=silent, goes up to 2 currently
|
||||||
qboolean save_temps; // save temporary files
|
qboolean save_temps; // save temporary files
|
||||||
qboolean files_dat; // generate files.dat
|
qboolean files_dat; // generate files.dat
|
||||||
|
qboolean traditional; // behave more like qcc
|
||||||
} options_t;
|
} options_t;
|
||||||
|
|
||||||
extern options_t options;
|
extern options_t options;
|
||||||
|
|
|
@ -192,7 +192,10 @@ emit_assign_expr (int oper, expr_t *e)
|
||||||
warning (e1, "assignment to constant %s (Moooooooo!)",
|
warning (e1, "assignment to constant %s (Moooooooo!)",
|
||||||
def_a->name);
|
def_a->name);
|
||||||
} else {
|
} 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);
|
def_b = emit_sub_expr (e2, def_a);
|
||||||
|
|
|
@ -1449,7 +1449,9 @@ function_expr (expr_t *e1, expr_t *e2)
|
||||||
if (parm_count > ftype->num_parms) {
|
if (parm_count > ftype->num_parms) {
|
||||||
return error (e1, "too many arguments");
|
return error (e1, "too many arguments");
|
||||||
} else if (parm_count < ftype->num_parms) {
|
} 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) {
|
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)
|
return_expr (function_t *f, expr_t *e)
|
||||||
{
|
{
|
||||||
if (!e) {
|
if (!e) {
|
||||||
if (f->def->type->aux_type != &type_void)
|
if (f->def->type->aux_type != &type_void) {
|
||||||
return error (e, "return from non-void function without a value");
|
if (options.traditional) {
|
||||||
} else {
|
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);
|
type_t *t = get_type (e);
|
||||||
|
|
||||||
if (f->def->type->aux_type == &type_void)
|
if (f->def->type->aux_type == &type_void)
|
||||||
|
@ -1737,10 +1748,14 @@ assign_expr (expr_t *e1, expr_t *e2)
|
||||||
convert_nil (e2, t2);
|
convert_nil (e2, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1 != t2)
|
if (t1 != t2) {
|
||||||
return type_mismatch (e1, e2, op);
|
if (!options.traditional || t1->type != ev_func || t2->type != ev_func)
|
||||||
else
|
return type_mismatch (e1, e2, op);
|
||||||
|
warning (e1, "assignment between disparate function types");
|
||||||
type = t1;
|
type = t1;
|
||||||
|
} else {
|
||||||
|
type = t1;
|
||||||
|
}
|
||||||
if (is_indirect (e1) && is_indirect (e2)) {
|
if (is_indirect (e1) && is_indirect (e2)) {
|
||||||
expr_t *temp = new_temp_def_expr (t1);
|
expr_t *temp = new_temp_def_expr (t1);
|
||||||
|
|
||||||
|
|
|
@ -216,34 +216,35 @@ typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
int value;
|
int value;
|
||||||
type_t *type;
|
type_t *type;
|
||||||
|
int traditional;
|
||||||
int version;
|
int version;
|
||||||
} keyword_t;
|
} keyword_t;
|
||||||
|
|
||||||
static keyword_t keywords[] = {
|
static keyword_t keywords[] = {
|
||||||
{"void", TYPE, &type_void, PROG_ID_VERSION},
|
{"void", TYPE, &type_void, 1, PROG_ID_VERSION},
|
||||||
{"float", TYPE, &type_float, PROG_ID_VERSION},
|
{"float", TYPE, &type_float, 1, PROG_ID_VERSION},
|
||||||
{"string", TYPE, &type_string, PROG_ID_VERSION},
|
{"string", TYPE, &type_string, 1, PROG_ID_VERSION},
|
||||||
{"vector", TYPE, &type_vector, PROG_ID_VERSION},
|
{"vector", TYPE, &type_vector, 1, PROG_ID_VERSION},
|
||||||
{"entity", TYPE, &type_entity, PROG_ID_VERSION},
|
{"entity", TYPE, &type_entity, 1, PROG_ID_VERSION},
|
||||||
{"quaternion", TYPE, &type_quaternion, PROG_VERSION},
|
{"quaternion", TYPE, &type_quaternion, 0, PROG_VERSION},
|
||||||
{"integer", TYPE, &type_integer, PROG_VERSION},
|
{"integer", TYPE, &type_integer, 0, PROG_VERSION},
|
||||||
{"function", TYPE, &type_function, PROG_VERSION},
|
{"function", TYPE, &type_function, 0, PROG_VERSION},
|
||||||
{"local", LOCAL, 0, PROG_ID_VERSION},
|
{"local", LOCAL, 0, 1, PROG_ID_VERSION},
|
||||||
{"return", RETURN, 0, PROG_ID_VERSION},
|
{"return", RETURN, 0, 1, PROG_ID_VERSION},
|
||||||
{"while", WHILE, 0, PROG_ID_VERSION},
|
{"while", WHILE, 0, 1, PROG_ID_VERSION},
|
||||||
{"do", DO, 0, PROG_ID_VERSION},
|
{"do", DO, 0, 1, PROG_ID_VERSION},
|
||||||
{"if", IF, 0, PROG_ID_VERSION},
|
{"if", IF, 0, 1, PROG_ID_VERSION},
|
||||||
{"else", ELSE, 0, PROG_ID_VERSION},
|
{"else", ELSE, 0, 1, PROG_ID_VERSION},
|
||||||
{"for", FOR, 0, PROG_ID_VERSION},
|
{"for", FOR, 0, 0, PROG_ID_VERSION},
|
||||||
{"break", BREAK, 0, PROG_ID_VERSION},
|
{"break", BREAK, 0, 0, PROG_ID_VERSION},
|
||||||
{"continue", CONTINUE, 0, PROG_ID_VERSION},
|
{"continue", CONTINUE, 0, 0, PROG_ID_VERSION},
|
||||||
{"switch", SWITCH, 0, PROG_ID_VERSION},
|
{"switch", SWITCH, 0, 0, PROG_ID_VERSION},
|
||||||
{"case", CASE, 0, PROG_ID_VERSION},
|
{"case", CASE, 0, 0, PROG_ID_VERSION},
|
||||||
{"default", DEFAULT, 0, PROG_ID_VERSION},
|
{"default", DEFAULT, 0, 0, PROG_ID_VERSION},
|
||||||
{"NIL", NIL, 0, PROG_ID_VERSION},
|
{"NIL", NIL, 0, 0, PROG_ID_VERSION},
|
||||||
{"struct", STRUCT, 0, PROG_VERSION},
|
{"struct", STRUCT, 0, 0, PROG_VERSION},
|
||||||
{"enum", ENUM, 0, PROG_ID_VERSION},
|
{"enum", ENUM, 0, 0, PROG_ID_VERSION},
|
||||||
{"typedef", TYPEDEF, 0, PROG_ID_VERSION},
|
{"typedef", TYPEDEF, 0, 0, PROG_ID_VERSION},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
@ -263,7 +264,8 @@ type_or_name (char *token)
|
||||||
int i;
|
int i;
|
||||||
keyword_tab = Hash_NewTable (1021, keyword_get_key, 0, 0);
|
keyword_tab = Hash_NewTable (1021, keyword_get_key, 0, 0);
|
||||||
for (i = 0; i < sizeof (keywords) / sizeof (keywords[0]); i++)
|
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]);
|
Hash_Add (keyword_tab, &keywords[i]);
|
||||||
}
|
}
|
||||||
keyword = Hash_Find (keyword_tab, token);
|
keyword = Hash_Find (keyword_tab, token);
|
||||||
|
|
|
@ -80,6 +80,7 @@ static struct option const long_options[] = {
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"version", no_argument, 0, 'V'},
|
{"version", no_argument, 0, 'V'},
|
||||||
{"files", no_argument, 0, 'F'},
|
{"files", no_argument, 0, 'F'},
|
||||||
|
{"traditional", no_argument, 0, 't'},
|
||||||
#ifdef USE_CPP
|
#ifdef USE_CPP
|
||||||
{"define", required_argument, 0, 'D'},
|
{"define", required_argument, 0, 'D'},
|
||||||
{"include", required_argument, 0, 'I'},
|
{"include", required_argument, 0, 'I'},
|
||||||
|
@ -857,6 +858,10 @@ DecodeArgs (int argc, char **argv)
|
||||||
case 'g': // debug
|
case 'g': // debug
|
||||||
options.code.debug = true;
|
options.code.debug = true;
|
||||||
break;
|
break;
|
||||||
|
case 't': // traditional
|
||||||
|
options.traditional = true;
|
||||||
|
options.code.progsversion = PROG_ID_VERSION;
|
||||||
|
break;
|
||||||
case 'C':{ // code options
|
case 'C':{ // code options
|
||||||
char *opts = strdup (optarg);
|
char *opts = strdup (optarg);
|
||||||
char *temp = strtok (opts, ",");
|
char *temp = strtok (opts, ",");
|
||||||
|
|
Loading…
Reference in a new issue