mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 07:11:41 +00:00
[qfcc] Support C's full type system
Along with QuakeC's, of course. This fixes type typeredef2 test (a lot of work for one little syntax error). Unfortunately, it came at the cost of requiring `>>` in front of state expressions on C-style functions (QuakeC-style functions are unaffected). Also, there are now two shift/reduce conflicts with structs and unions (but these same conflicts are in gcc 3.4). This has highlighted the need for having the equivalent of the expression tree for the declaration system as there are now several hacks to deal with the separation of types and declarators. But that's a job for another week. The grammar constructs for declarations come from gcc 3.4's parser (I think it's the last version of gcc that used bison. Also, 3.4 is still GPL 2, so no chance of an issue there).
This commit is contained in:
parent
02432311c5
commit
fc7c96d208
11 changed files with 920 additions and 787 deletions
|
@ -148,7 +148,7 @@ param_t *param_append_identifiers (param_t *params, struct symbol_s *idents,
|
|||
param_t *reverse_params (param_t *params);
|
||||
param_t *append_params (param_t *params, param_t *more_params);
|
||||
param_t *copy_params (param_t *params);
|
||||
struct type_s *parse_params (struct type_s *type, param_t *params);
|
||||
struct type_s *parse_params (struct type_s *return_type, param_t *params);
|
||||
param_t *check_params (param_t *params);
|
||||
|
||||
enum storage_class_e;
|
||||
|
|
|
@ -43,6 +43,8 @@ typedef struct {
|
|||
void (*emit) (struct def_s *def, void *data, int index);
|
||||
} struct_def_t;
|
||||
|
||||
struct symtab_s *start_struct (int *su, struct symbol_s *tag,
|
||||
struct symtab_s *parent);
|
||||
struct symbol_s *find_struct (int su, struct symbol_s *tag,
|
||||
struct type_s *type);
|
||||
struct symbol_s *build_struct (int su, struct symbol_s *tag,
|
||||
|
|
|
@ -244,6 +244,10 @@ symtab_t *symtab_flat_copy (symtab_t *symtab, symtab_t *parent);
|
|||
symbol_t *make_symbol (const char *name, struct type_s *type,
|
||||
struct defspace_s *space, enum storage_class_e storage);
|
||||
|
||||
struct specifier_s;
|
||||
symbol_t *declare_symbol (struct specifier_s spec, struct expr_s *init,
|
||||
symtab_t *symtab);
|
||||
|
||||
///@}
|
||||
|
||||
#endif//__symtab_h
|
||||
|
|
|
@ -90,10 +90,10 @@ typedef struct type_s {
|
|||
struct def_s *type_def; ///< offset of qfo encodoing
|
||||
} type_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct specifier_s {
|
||||
type_t *type;
|
||||
struct param_s *params;
|
||||
struct symbol_s *sym; ///< for dealing with "int id" etc
|
||||
struct symbol_s *sym;
|
||||
storage_class_t storage;
|
||||
union {
|
||||
struct {
|
||||
|
@ -105,6 +105,7 @@ typedef struct {
|
|||
unsigned is_long:1;
|
||||
unsigned is_typedef:1;
|
||||
unsigned is_overload:1;
|
||||
unsigned is_function:1;//FIXME do proper void(*)() -> ev_func
|
||||
unsigned nosave:1;
|
||||
unsigned no_va_list:1;
|
||||
unsigned void_return:1;
|
||||
|
@ -156,6 +157,8 @@ void chain_type (type_t *type);
|
|||
level.
|
||||
*/
|
||||
type_t *append_type (type_t *type, type_t *new);
|
||||
void set_func_type_attrs (type_t *func, specifier_t spec);
|
||||
specifier_t default_type (specifier_t spec, struct symbol_s *sym);
|
||||
type_t *find_type (type_t *new);
|
||||
void new_typedef (const char *name, type_t *type);
|
||||
type_t *field_type (type_t *aux);
|
||||
|
|
|
@ -100,7 +100,7 @@ new_param (const char *selector, type_t *type, const char *name)
|
|||
ALLOC (4096, param_t, params, param);
|
||||
param->next = 0;
|
||||
param->selector = selector;
|
||||
param->type = type;
|
||||
param->type = find_type (type);
|
||||
param->name = name;
|
||||
|
||||
return param;
|
||||
|
@ -173,23 +173,23 @@ copy_params (param_t *params)
|
|||
}
|
||||
|
||||
type_t *
|
||||
parse_params (type_t *type, param_t *parms)
|
||||
parse_params (type_t *return_type, param_t *parms)
|
||||
{
|
||||
param_t *p;
|
||||
type_t *new;
|
||||
type_t *ptype;
|
||||
int count = 0;
|
||||
|
||||
if (type && is_class (type)) {
|
||||
if (return_type && is_class (return_type)) {
|
||||
error (0, "cannot return an object (forgot *?)");
|
||||
type = &type_id;
|
||||
return_type = &type_id;
|
||||
}
|
||||
|
||||
new = new_type ();
|
||||
new->type = ev_func;
|
||||
new->alignment = 1;
|
||||
new->width = 1;
|
||||
new->t.func.type = type;
|
||||
new->t.func.type = return_type;
|
||||
new->t.func.num_params = 0;
|
||||
|
||||
for (p = parms; p; p = p->next) {
|
||||
|
|
|
@ -357,7 +357,7 @@ static keyword_t rua_keywords[] = {
|
|||
// If not compiling for the QuakeForge VM, or if Ruamoko has been disabled,
|
||||
// then they will be unavailable as keywords.
|
||||
static keyword_t obj_keywords[] = {
|
||||
{"id", OBJECT, .spec = { .type = &type_id } },
|
||||
{"id", OBJECT_NAME, .spec = { .type = &type_id } },
|
||||
{"Class", TYPE_SPEC, .spec = { .type = &type_Class } },
|
||||
{"Method", TYPE_SPEC, .spec = { .type = &type_method } },
|
||||
{"Super", TYPE_SPEC, .spec = { .type = &type_super } },
|
||||
|
@ -462,7 +462,7 @@ process_keyword (keyword_t *keyword, const char *token)
|
|||
{
|
||||
if (keyword->value == STRUCT) {
|
||||
qc_yylval.op = token[0];
|
||||
} else if (keyword->value == OBJECT) {
|
||||
} else if (keyword->value == OBJECT_NAME) {
|
||||
symbol_t *sym;
|
||||
|
||||
sym = symtab_lookup (current_symtab, token);
|
||||
|
@ -472,7 +472,11 @@ process_keyword (keyword_t *keyword, const char *token)
|
|||
// be redefinable when in an enclosing scope.
|
||||
if (sym->sy_type == sy_name) {
|
||||
// this is the global id (object)
|
||||
return OBJECT;
|
||||
qc_yylval.spec = (specifier_t) {
|
||||
.type = sym->type,
|
||||
.sym = sym,
|
||||
};
|
||||
return OBJECT_NAME;
|
||||
} else if (sym->sy_type == sy_type) {
|
||||
// id has been redeclared via a typedef
|
||||
qc_yylval.spec = (specifier_t) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -98,6 +98,33 @@ find_tag (ty_meta_e meta, symbol_t *tag, type_t *type)
|
|||
return sym;
|
||||
}
|
||||
|
||||
symtab_t *
|
||||
start_struct (int *su, symbol_t *tag, symtab_t *parent)
|
||||
{
|
||||
symbol_t *sym;
|
||||
sym = find_struct (*su, tag, 0);
|
||||
if (!sym->table) {
|
||||
symtab_addsymbol (parent, sym);
|
||||
} else {
|
||||
if (!sym->type) {
|
||||
internal_error (0, "broken structure symbol?");
|
||||
}
|
||||
if (tag) {
|
||||
tag->type = sym->type;
|
||||
}
|
||||
if (sym->type->meta == ty_enum
|
||||
|| (sym->type->meta == ty_struct && sym->type->t.symtab)) {
|
||||
error (0, "%s %s redefined",
|
||||
*su == 's' ? "struct" : "union", tag->name);
|
||||
*su = 0;
|
||||
} else if (sym->type->meta != ty_struct) {
|
||||
internal_error (0, "%s is not a struct or union",
|
||||
tag->name);
|
||||
}
|
||||
}
|
||||
return new_symtab (parent, stab_struct);
|
||||
}
|
||||
|
||||
symbol_t *
|
||||
find_struct (int su, symbol_t *tag, type_t *type)
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "tools/qfcc/include/function.h"
|
||||
#include "tools/qfcc/include/qfcc.h"
|
||||
#include "tools/qfcc/include/reloc.h"
|
||||
#include "tools/qfcc/include/shared.h"
|
||||
#include "tools/qfcc/include/strpool.h"
|
||||
#include "tools/qfcc/include/symtab.h"
|
||||
#include "tools/qfcc/include/type.h"
|
||||
|
@ -243,3 +244,56 @@ make_symbol (const char *name, type_t *type, defspace_t *space,
|
|||
sym->sy_type = sy_var;
|
||||
return sym;
|
||||
}
|
||||
|
||||
symbol_t *
|
||||
declare_symbol (specifier_t spec, expr_t *init, symtab_t *symtab)
|
||||
{
|
||||
symbol_t *s = spec.sym;
|
||||
defspace_t *space = symtab->space;
|
||||
|
||||
if (s->table) {
|
||||
// due to the way declarations work, we need a new symbol at all times.
|
||||
// redelcarations will be checked later
|
||||
s = new_symbol (s->name);
|
||||
}
|
||||
|
||||
spec = default_type (spec, s);
|
||||
if (!spec.storage) {
|
||||
spec.storage = current_storage;
|
||||
}
|
||||
if (spec.storage == sc_static) {
|
||||
space = pr.near_data;
|
||||
}
|
||||
|
||||
//FIXME is_function is bad (this whole implementation of handling
|
||||
//function prototypes is bad)
|
||||
if (spec.is_function && is_func (spec.type)) {
|
||||
set_func_type_attrs (spec.type, spec);
|
||||
}
|
||||
s->type = spec.type;
|
||||
|
||||
if (spec.is_typedef) {
|
||||
if (init) {
|
||||
error (0, "typedef %s is initialized", s->name);
|
||||
}
|
||||
s->sy_type = sy_type;
|
||||
s->type = find_type (s->type);
|
||||
s->type = find_type (alias_type (s->type, s->type, s->name));
|
||||
symtab_addsymbol (symtab, s);
|
||||
} else {
|
||||
if (spec.is_function && is_func (s->type)) {
|
||||
if (init) {
|
||||
error (0, "function %s is initialized", s->name);
|
||||
}
|
||||
s->type = find_type (s->type);
|
||||
s = function_symbol (s, spec.is_overload, 1);
|
||||
} else {
|
||||
s->type = find_type (s->type);
|
||||
initialize_def (s, init, space, spec.storage, symtab);
|
||||
if (s->s.def) {
|
||||
s->s.def->nosave |= spec.nosave;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -436,6 +436,82 @@ types_same (type_t *a, type_t *b)
|
|||
internal_error (0, "we be broke");
|
||||
}
|
||||
|
||||
void
|
||||
set_func_type_attrs (type_t *func, specifier_t spec)
|
||||
{
|
||||
func->t.func.no_va_list = spec.no_va_list;
|
||||
func->t.func.void_return = spec.void_return;
|
||||
}
|
||||
|
||||
specifier_t
|
||||
default_type (specifier_t spec, symbol_t *sym)
|
||||
{
|
||||
if (spec.type) {
|
||||
if (is_float (spec.type) && !spec.multi_type) {
|
||||
// no modifieres allowed
|
||||
if (spec.is_unsigned) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both unsigned and float in declaration specifiers");
|
||||
} else if (spec.is_signed) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both signed and float in declaration specifiers");
|
||||
} else if (spec.is_short) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both short and float in declaration specifiers");
|
||||
} else if (spec.is_long) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both long and float in declaration specifiers");
|
||||
}
|
||||
}
|
||||
if (is_double (spec.type)) {
|
||||
// long is allowed but ignored
|
||||
if (spec.is_unsigned) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both unsigned and double in declaration specifiers");
|
||||
} else if (spec.is_signed) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both signed and double in declaration specifiers");
|
||||
} else if (spec.is_short) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both short and double in declaration specifiers");
|
||||
}
|
||||
}
|
||||
if (is_int (spec.type)) {
|
||||
// signed and short are ignored
|
||||
if (spec.is_unsigned && spec.is_long) {
|
||||
spec.type = &type_ulong;
|
||||
} else if (spec.is_long) {
|
||||
spec.type = &type_long;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (spec.is_long) {
|
||||
if (spec.is_unsigned) {
|
||||
spec.type = type_ulong_uint;
|
||||
} else {
|
||||
spec.type = type_long_int;
|
||||
}
|
||||
} else {
|
||||
if (spec.is_unsigned) {
|
||||
spec.type = &type_uint;
|
||||
} else if (spec.is_signed || spec.is_short) {
|
||||
spec.type = &type_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!spec.type) {
|
||||
spec.type = type_default;
|
||||
if (sym) {
|
||||
warning (0, "type defaults to '%s' in declaration of '%s'",
|
||||
type_default->name, sym->name);
|
||||
} else {
|
||||
warning (0, "type defaults to '%s' in abstract declaration",
|
||||
type_default->name);
|
||||
}
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
|
||||
/*
|
||||
find_type
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ $frame frame0 frame1 frame2 frame3
|
|||
|
||||
void
|
||||
state0 (void)
|
||||
[$frame1, state1]
|
||||
>> [$frame1, state1]
|
||||
{
|
||||
if (self.frame != $frame1 || self.think != state1
|
||||
|| self.nextthink != 0.1f) {
|
||||
|
@ -21,7 +21,7 @@ state0 (void)
|
|||
|
||||
void
|
||||
state1 (void)
|
||||
[$frame2, state2, 0.2f]
|
||||
>> [$frame2, state2, 0.2f]
|
||||
{
|
||||
if (self.frame != $frame2 || self.think != state2
|
||||
|| self.nextthink != 0.2f) {
|
||||
|
@ -32,7 +32,7 @@ state1 (void)
|
|||
|
||||
void
|
||||
state2 (void)
|
||||
[$frame0, state0, 0.5f]
|
||||
>> [$frame0, state0, 0.5f]
|
||||
{
|
||||
if (self.frame != $frame0 || self.think != state0
|
||||
|| self.nextthink != 0.5f) {
|
||||
|
|
Loading…
Reference in a new issue