mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 05:01:24 +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 {
|
||||
bool multi_type:1;
|
||||
bool multi_store:1;
|
||||
bool multi_generic:1;
|
||||
bool is_signed:1;
|
||||
bool is_unsigned:1;
|
||||
bool is_short:1;
|
||||
|
@ -66,6 +67,7 @@ typedef struct specifier_s {
|
|||
bool is_typedef:1;
|
||||
bool is_overload:1;
|
||||
bool is_generic:1;
|
||||
bool is_generic_block:1;
|
||||
bool is_function:1;//FIXME do proper void(*)() -> ev_func
|
||||
bool nosave:1;
|
||||
bool no_va_list:1;
|
||||
|
|
|
@ -105,8 +105,8 @@ static void
|
|||
check_generic_param (genparam_t *param, genfunc_t *genfunc)
|
||||
{
|
||||
if (param->gentype < 0 || param->gentype >= genfunc->num_types) {
|
||||
internal_error (0, "invalid type index %s for %s",
|
||||
param->name, genfunc->name);
|
||||
internal_error (0, "invalid type index %d on %s for %s",
|
||||
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) {
|
||||
num_params++;
|
||||
}
|
||||
auto generic_tab = current_symtab;
|
||||
auto generic_tab = spec.symtab;
|
||||
for (auto s = generic_tab->symbols; s; s = s->next) {
|
||||
bool found = false;
|
||||
for (auto q = &ret_param; q; q = q->next) {
|
||||
|
@ -309,7 +309,7 @@ parse_generic_function (const char *name, specifier_t spec)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (!spec.is_generic_block && !found) {
|
||||
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 const expr_t *break_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
|
||||
type_spec (const type_t *type)
|
||||
|
@ -291,6 +309,7 @@ generic_spec (void)
|
|||
.symtab = new_symtab (current_symtab, stab_local),
|
||||
.is_generic = true,
|
||||
};
|
||||
generic_symtab = spec.symtab;
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
@ -348,6 +367,12 @@ spec_merge (specifier_t spec, specifier_t new)
|
|||
spec.storage = new.storage;
|
||||
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)
|
||||
|| (new.is_signed && spec.is_unsigned)) {
|
||||
if (!spec.multi_type) {
|
||||
|
@ -398,6 +423,9 @@ function_spec (specifier_t spec, param_t *params)
|
|||
spec.sym->params = 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_generic = generic_scope;
|
||||
spec.is_generic_block = generic_block;
|
||||
spec.symtab = generic_symtab;
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
@ -581,13 +609,14 @@ program
|
|||
external_def_list
|
||||
: /* empty */
|
||||
{
|
||||
current_symtab = pr.symtab;
|
||||
if (!generic_block) {
|
||||
current_symtab = pr.symtab;
|
||||
}
|
||||
}
|
||||
| external_def_list external_def
|
||||
{
|
||||
if (generic_scope) {
|
||||
generic_scope = false;
|
||||
current_symtab = current_symtab->parent;
|
||||
if (generic_scope && !generic_block) {
|
||||
end_generic_scope ();
|
||||
}
|
||||
}
|
||||
| external_def_list obj_def
|
||||
|
@ -599,10 +628,11 @@ external_def
|
|||
| storage_class '{' save_storage
|
||||
{
|
||||
current_storage = $1.storage;
|
||||
generic_block = generic_scope;
|
||||
}
|
||||
external_def_list '}' ';'
|
||||
{
|
||||
current_storage = $3.storage;
|
||||
restore_storage ($3);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -773,7 +803,7 @@ qc_code_func
|
|||
build_code_function ($1, $3, $6);
|
||||
current_symtab = $<funcstate>5.symtab;
|
||||
current_func = $<funcstate>5.function;
|
||||
current_storage = $4.storage;
|
||||
restore_storage ($4);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1054,6 +1084,7 @@ save_storage
|
|||
: /* emtpy */
|
||||
{
|
||||
$$.storage = current_storage;
|
||||
$$.is_generic = generic_block;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1080,7 +1111,7 @@ function_body
|
|||
build_code_function ($<symbol>2, $1, $5);
|
||||
current_symtab = $<funcstate>4.symtab;
|
||||
current_func = $<funcstate>4.function;
|
||||
current_storage = $3.storage;
|
||||
restore_storage ($3);
|
||||
}
|
||||
| '=' '#' expr ';'
|
||||
{
|
||||
|
@ -1100,13 +1131,14 @@ storage_class
|
|||
| GENERIC '(' { $<spec>$ = generic_spec (); }
|
||||
generic_param_list ')'
|
||||
{
|
||||
$$ = $<spec>3;
|
||||
|
||||
if (generic_scope) {
|
||||
error (0, "multiple @generic in declaration");
|
||||
$$.multi_generic = true;
|
||||
} else {
|
||||
generic_scope = true;
|
||||
current_symtab = $<spec>3.symtab;
|
||||
}
|
||||
$$ = $<spec>3;
|
||||
}
|
||||
| ATTRIBUTE '(' attribute_list ')'
|
||||
{
|
||||
|
@ -2438,7 +2470,7 @@ methoddef
|
|||
build_code_function ($<symbol>4, $3, $7);
|
||||
current_symtab = $<funcstate>6.symtab;
|
||||
current_func = $<funcstate>6.function;
|
||||
current_storage = $5.storage;
|
||||
restore_storage ($5);
|
||||
}
|
||||
| ci methoddecl '=' '#' const ';'
|
||||
{
|
||||
|
@ -2858,7 +2890,6 @@ qc_keyword_or_id (QC_YYSTYPE *lval, const char *token)
|
|||
static hashtab_t *rua_keyword_tab;
|
||||
|
||||
keyword_t *keyword = 0;
|
||||
symbol_t *sym;
|
||||
|
||||
if (!keyword_tab) {
|
||||
size_t i;
|
||||
|
@ -2908,9 +2939,17 @@ qc_keyword_or_id (QC_YYSTYPE *lval, const char *token)
|
|||
if (token[0] == '@') {
|
||||
return '@';
|
||||
}
|
||||
sym = symtab_lookup (current_symtab, token);
|
||||
if (!sym)
|
||||
|
||||
symbol_t *sym = nullptr;
|
||||
if (generic_symtab) {
|
||||
sym = symtab_lookup (generic_symtab, token);
|
||||
}
|
||||
if (!sym) {
|
||||
sym = symtab_lookup (current_symtab, token);
|
||||
}
|
||||
if (!sym) {
|
||||
sym = new_symbol (token);
|
||||
}
|
||||
lval->symbol = sym;
|
||||
if (sym->sy_type == sy_type) {
|
||||
lval->spec = (specifier_t) {
|
||||
|
|
Loading…
Reference in a new issue