mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[qfcc] Support generic scope blocks
That is, `@generic(...) { ... };`, which is handy for bulk declarations (such as for glsl). This proved to be a lot harder than expected, I suspect handling of specifiers needs a lot of work.
This commit is contained in:
parent
0d063c3290
commit
58bf1ee64e
3 changed files with 59 additions and 18 deletions
|
@ -59,6 +59,7 @@ typedef struct specifier_s {
|
||||||
struct {
|
struct {
|
||||||
bool multi_type:1;
|
bool multi_type:1;
|
||||||
bool multi_store:1;
|
bool multi_store:1;
|
||||||
|
bool multi_generic:1;
|
||||||
bool is_signed:1;
|
bool is_signed:1;
|
||||||
bool is_unsigned:1;
|
bool is_unsigned:1;
|
||||||
bool is_short:1;
|
bool is_short:1;
|
||||||
|
@ -66,6 +67,7 @@ typedef struct specifier_s {
|
||||||
bool is_typedef:1;
|
bool is_typedef:1;
|
||||||
bool is_overload:1;
|
bool is_overload:1;
|
||||||
bool is_generic:1;
|
bool is_generic:1;
|
||||||
|
bool is_generic_block:1;
|
||||||
bool is_function:1;//FIXME do proper void(*)() -> ev_func
|
bool is_function:1;//FIXME do proper void(*)() -> ev_func
|
||||||
bool nosave:1;
|
bool nosave:1;
|
||||||
bool no_va_list:1;
|
bool no_va_list:1;
|
||||||
|
|
|
@ -105,8 +105,8 @@ static void
|
||||||
check_generic_param (genparam_t *param, genfunc_t *genfunc)
|
check_generic_param (genparam_t *param, genfunc_t *genfunc)
|
||||||
{
|
{
|
||||||
if (param->gentype < 0 || param->gentype >= genfunc->num_types) {
|
if (param->gentype < 0 || param->gentype >= genfunc->num_types) {
|
||||||
internal_error (0, "invalid type index %s for %s",
|
internal_error (0, "invalid type index %d on %s for %s",
|
||||||
param->name, genfunc->name);
|
param->gentype, param->name, genfunc->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ parse_generic_function (const char *name, specifier_t spec)
|
||||||
for (auto p = &ret_param; p; p = p->next) {
|
for (auto p = &ret_param; p; p = p->next) {
|
||||||
num_params++;
|
num_params++;
|
||||||
}
|
}
|
||||||
auto generic_tab = current_symtab;
|
auto generic_tab = spec.symtab;
|
||||||
for (auto s = generic_tab->symbols; s; s = s->next) {
|
for (auto s = generic_tab->symbols; s; s = s->next) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto q = &ret_param; q; q = q->next) {
|
for (auto q = &ret_param; q; q = q->next) {
|
||||||
|
@ -309,7 +309,7 @@ parse_generic_function (const char *name, specifier_t spec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!spec.is_generic_block && !found) {
|
||||||
warning (0, "generic parameter %s not used", s->name);
|
warning (0, "generic parameter %s not used", s->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,25 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
|
||||||
static switch_block_t *switch_block;
|
static switch_block_t *switch_block;
|
||||||
static const expr_t *break_label;
|
static const expr_t *break_label;
|
||||||
static const expr_t *continue_label;
|
static const expr_t *continue_label;
|
||||||
static bool generic_scope;
|
static bool generic_scope, generic_block;
|
||||||
|
static symtab_t *generic_symtab;
|
||||||
|
|
||||||
|
static void
|
||||||
|
end_generic_scope (void)
|
||||||
|
{
|
||||||
|
generic_scope = false;
|
||||||
|
generic_symtab = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
restore_storage (specifier_t st)
|
||||||
|
{
|
||||||
|
if (generic_block && !st.is_generic) {
|
||||||
|
end_generic_scope ();
|
||||||
|
}
|
||||||
|
generic_block = st.is_generic;
|
||||||
|
current_storage = st.storage;
|
||||||
|
}
|
||||||
|
|
||||||
static specifier_t
|
static specifier_t
|
||||||
type_spec (const type_t *type)
|
type_spec (const type_t *type)
|
||||||
|
@ -291,6 +309,7 @@ generic_spec (void)
|
||||||
.symtab = new_symtab (current_symtab, stab_local),
|
.symtab = new_symtab (current_symtab, stab_local),
|
||||||
.is_generic = true,
|
.is_generic = true,
|
||||||
};
|
};
|
||||||
|
generic_symtab = spec.symtab;
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,6 +367,12 @@ spec_merge (specifier_t spec, specifier_t new)
|
||||||
spec.storage = new.storage;
|
spec.storage = new.storage;
|
||||||
spec.is_typedef = new.is_typedef;
|
spec.is_typedef = new.is_typedef;
|
||||||
}
|
}
|
||||||
|
if (new.is_generic) {
|
||||||
|
if (spec.is_generic && !spec.multi_generic) {
|
||||||
|
error (0, "multiple @generic in declaration");
|
||||||
|
spec.multi_generic = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
if ((new.is_unsigned && spec.is_signed)
|
if ((new.is_unsigned && spec.is_signed)
|
||||||
|| (new.is_signed && spec.is_unsigned)) {
|
|| (new.is_signed && spec.is_unsigned)) {
|
||||||
if (!spec.multi_type) {
|
if (!spec.multi_type) {
|
||||||
|
@ -398,6 +423,9 @@ function_spec (specifier_t spec, param_t *params)
|
||||||
spec.sym->params = params;
|
spec.sym->params = params;
|
||||||
spec.sym->type = append_type (spec.sym->type, parse_params (0, params));
|
spec.sym->type = append_type (spec.sym->type, parse_params (0, params));
|
||||||
spec.is_function = true; //FIXME do proper void(*)() -> ev_func
|
spec.is_function = true; //FIXME do proper void(*)() -> ev_func
|
||||||
|
spec.is_generic = generic_scope;
|
||||||
|
spec.is_generic_block = generic_block;
|
||||||
|
spec.symtab = generic_symtab;
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,13 +609,14 @@ program
|
||||||
external_def_list
|
external_def_list
|
||||||
: /* empty */
|
: /* empty */
|
||||||
{
|
{
|
||||||
|
if (!generic_block) {
|
||||||
current_symtab = pr.symtab;
|
current_symtab = pr.symtab;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
| external_def_list external_def
|
| external_def_list external_def
|
||||||
{
|
{
|
||||||
if (generic_scope) {
|
if (generic_scope && !generic_block) {
|
||||||
generic_scope = false;
|
end_generic_scope ();
|
||||||
current_symtab = current_symtab->parent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| external_def_list obj_def
|
| external_def_list obj_def
|
||||||
|
@ -599,10 +628,11 @@ external_def
|
||||||
| storage_class '{' save_storage
|
| storage_class '{' save_storage
|
||||||
{
|
{
|
||||||
current_storage = $1.storage;
|
current_storage = $1.storage;
|
||||||
|
generic_block = generic_scope;
|
||||||
}
|
}
|
||||||
external_def_list '}' ';'
|
external_def_list '}' ';'
|
||||||
{
|
{
|
||||||
current_storage = $3.storage;
|
restore_storage ($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -773,7 +803,7 @@ qc_code_func
|
||||||
build_code_function ($1, $3, $6);
|
build_code_function ($1, $3, $6);
|
||||||
current_symtab = $<funcstate>5.symtab;
|
current_symtab = $<funcstate>5.symtab;
|
||||||
current_func = $<funcstate>5.function;
|
current_func = $<funcstate>5.function;
|
||||||
current_storage = $4.storage;
|
restore_storage ($4);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1054,6 +1084,7 @@ save_storage
|
||||||
: /* emtpy */
|
: /* emtpy */
|
||||||
{
|
{
|
||||||
$$.storage = current_storage;
|
$$.storage = current_storage;
|
||||||
|
$$.is_generic = generic_block;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1080,7 +1111,7 @@ function_body
|
||||||
build_code_function ($<symbol>2, $1, $5);
|
build_code_function ($<symbol>2, $1, $5);
|
||||||
current_symtab = $<funcstate>4.symtab;
|
current_symtab = $<funcstate>4.symtab;
|
||||||
current_func = $<funcstate>4.function;
|
current_func = $<funcstate>4.function;
|
||||||
current_storage = $3.storage;
|
restore_storage ($3);
|
||||||
}
|
}
|
||||||
| '=' '#' expr ';'
|
| '=' '#' expr ';'
|
||||||
{
|
{
|
||||||
|
@ -1100,13 +1131,14 @@ storage_class
|
||||||
| GENERIC '(' { $<spec>$ = generic_spec (); }
|
| GENERIC '(' { $<spec>$ = generic_spec (); }
|
||||||
generic_param_list ')'
|
generic_param_list ')'
|
||||||
{
|
{
|
||||||
|
$$ = $<spec>3;
|
||||||
|
|
||||||
if (generic_scope) {
|
if (generic_scope) {
|
||||||
error (0, "multiple @generic in declaration");
|
error (0, "multiple @generic in declaration");
|
||||||
|
$$.multi_generic = true;
|
||||||
} else {
|
} else {
|
||||||
generic_scope = true;
|
generic_scope = true;
|
||||||
current_symtab = $<spec>3.symtab;
|
|
||||||
}
|
}
|
||||||
$$ = $<spec>3;
|
|
||||||
}
|
}
|
||||||
| ATTRIBUTE '(' attribute_list ')'
|
| ATTRIBUTE '(' attribute_list ')'
|
||||||
{
|
{
|
||||||
|
@ -2438,7 +2470,7 @@ methoddef
|
||||||
build_code_function ($<symbol>4, $3, $7);
|
build_code_function ($<symbol>4, $3, $7);
|
||||||
current_symtab = $<funcstate>6.symtab;
|
current_symtab = $<funcstate>6.symtab;
|
||||||
current_func = $<funcstate>6.function;
|
current_func = $<funcstate>6.function;
|
||||||
current_storage = $5.storage;
|
restore_storage ($5);
|
||||||
}
|
}
|
||||||
| ci methoddecl '=' '#' const ';'
|
| ci methoddecl '=' '#' const ';'
|
||||||
{
|
{
|
||||||
|
@ -2858,7 +2890,6 @@ qc_keyword_or_id (QC_YYSTYPE *lval, const char *token)
|
||||||
static hashtab_t *rua_keyword_tab;
|
static hashtab_t *rua_keyword_tab;
|
||||||
|
|
||||||
keyword_t *keyword = 0;
|
keyword_t *keyword = 0;
|
||||||
symbol_t *sym;
|
|
||||||
|
|
||||||
if (!keyword_tab) {
|
if (!keyword_tab) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -2908,9 +2939,17 @@ qc_keyword_or_id (QC_YYSTYPE *lval, const char *token)
|
||||||
if (token[0] == '@') {
|
if (token[0] == '@') {
|
||||||
return '@';
|
return '@';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
symbol_t *sym = nullptr;
|
||||||
|
if (generic_symtab) {
|
||||||
|
sym = symtab_lookup (generic_symtab, token);
|
||||||
|
}
|
||||||
|
if (!sym) {
|
||||||
sym = symtab_lookup (current_symtab, token);
|
sym = symtab_lookup (current_symtab, token);
|
||||||
if (!sym)
|
}
|
||||||
|
if (!sym) {
|
||||||
sym = new_symbol (token);
|
sym = new_symbol (token);
|
||||||
|
}
|
||||||
lval->symbol = sym;
|
lval->symbol = sym;
|
||||||
if (sym->sy_type == sy_type) {
|
if (sym->sy_type == sy_type) {
|
||||||
lval->spec = (specifier_t) {
|
lval->spec = (specifier_t) {
|
||||||
|
|
Loading…
Reference in a new issue