0
0
Fork 0
mirror of https://git.code.sf.net/p/quake/quakeforge synced 2025-04-11 11:51:50 +00:00

[qfcc] Implement generic type parsing

The semantics are only partially implemented (generic types not yet
generated), but the generic scope for function declarations seems to be
working as intended in that it gets inserted in the scope chain and
removed at the end of the declaration.
This commit is contained in:
Bill Currie 2024-04-25 16:10:43 +09:00
parent 029b8b1667
commit 45d4b12e7a
2 changed files with 59 additions and 1 deletions
tools/qfcc

View file

@ -32,6 +32,8 @@
#define __specifier_h
typedef struct type_s type_t;
typedef struct symbol_s symbol_t;
typedef struct symtab_s symtab_t;
/** Specify the storage class of a def.
*/
@ -48,7 +50,8 @@ typedef enum storage_class_e {
typedef struct specifier_s {
const type_t *type;
struct param_s *params;
struct symbol_s *sym;
symbol_t *sym;
symtab_t *symtab;
storage_class_t storage;
union {
struct {

View file

@ -160,6 +160,7 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%token CLASS DEFS ENCODE END IMPLEMENTATION INTERFACE PRIVATE
%token PROTECTED PROTOCOL PUBLIC SELECTOR REFERENCE SELF THIS
%token GENERIC
%token AT_FIELD AT_POINTER AT_ARRAY
%token AT_BASE AT_WIDTH AT_VECTOR AT_ROWS AT_COLS AT_MATRIX
%token AT_INT AT_UINT AT_BOOL AT_FLOAT
@ -176,6 +177,7 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%type <spec> param_declarator_nostarttypename
%type <spec> absdecl absdecl1 direct_absdecl typename ptr_spec copy_spec
%type <spec> qc_comma
%type <symbol> generic_param
%type <type> type_param type_expr type_ref
%type <attribute> attribute_list attribute
@ -238,6 +240,7 @@ 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 specifier_t
make_spec (const type_t *type, storage_class_t storage, int is_typedef,
@ -537,6 +540,12 @@ external_def_list
current_symtab = pr.symtab;
}
| external_def_list external_def
{
if (generic_scope) {
generic_scope = false;
current_symtab = current_symtab->parent;
}
}
| external_def_list obj_def
;
@ -1019,12 +1028,51 @@ storage_class
| SYSTEM { $$ = make_spec (0, sc_system, 0, 0); }
| TYPEDEF { $$ = make_spec (0, sc_global, 1, 0); }
| OVERLOAD { $$ = make_spec (0, current_storage, 0, 1); }
| GENERIC '('
{
auto spec = make_spec (0, current_storage, 0, 0);
spec.symtab = new_symtab (current_symtab, stab_local);
$<spec>$ = spec;
}
generic_param_list ')'
{
if (generic_scope) {
error (0, "multiple @generic in declaration");
} else {
generic_scope = true;
current_symtab = $<spec>3.symtab;
}
$$ = make_spec (0, current_storage, 0, 0);
}
| ATTRIBUTE '(' attribute_list ')'
{
$$ = parse_attributes ($3);
}
;
generic_param_list
: generic_param
{
auto spec = $<spec>0;
symtab_addsymbol (spec.symtab, $1);
}
| generic_param_list ',' generic_param
{
auto spec = $<spec>0;
symtab_addsymbol (spec.symtab, $3);
}
;
generic_param
: NAME { $$ = $1; }
| NAME '=' generic_type { $$ = $1; }
;
generic_type
: type_expr
| '[' type_list ']'
;
type_expr
: AT_FIELD '(' type_param ')' { $$ = field_type ($3); }
| AT_POINTER '(' type_param ')' { $$ = pointer_type ($3); }
@ -1079,10 +1127,16 @@ type_param
| type_ref
;
type_list
: type_ref
| type_list ',' type_ref
;
type_ref
: TYPE_SPEC { $$ = $1.type; }
| TYPE_NAME { $$ = $1.type; }
| CLASS_NAME { $$ = $1->type; }
| NAME { internal_error (nullptr, "not implemented"); }
;
attribute_list
@ -2654,6 +2708,7 @@ static keyword_t qf_keywords[] = {
{"@dual", QC_DUAL, },
{"@undual", QC_UNDUAL, },
{"@generic", QC_GENERIC, },
{"@field", QC_AT_FIELD, },
{"@pointer", QC_AT_POINTER, },
{"@array", QC_AT_ARRAY, },