diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h index 53b42f150..7a6904f1a 100644 --- a/tools/qfcc/include/symtab.h +++ b/tools/qfcc/include/symtab.h @@ -56,8 +56,14 @@ typedef enum { sy_expr, ///< symbol refers to an expression sy_func, ///< symbol refers to a function sy_class, ///< symbol refers to a class + sy_convert, ///< symbol refers to a conversion function } sy_type_e; +typedef struct symconv_s { + struct expr_s *(*conv) (struct symbol_s *symbol, void *data); + void *data; +} symconv_t; + typedef struct symbol_s { struct symbol_s *next; ///< chain of symbols in symbol table struct symtab_s *table; ///< symbol table that owns this symbol @@ -72,6 +78,7 @@ typedef struct symbol_s { struct ex_value_s *value; ///< sy_const struct expr_s *expr; ///< sy_expr struct function_s *func; ///< sy_func + symconv_t convert; ///< sy_convert } s; } symbol_t; @@ -92,6 +99,7 @@ typedef struct symtab_s { symbol_t *symbols; ///< chain of symbols in this table symbol_t **symtail; ///< keep chain in declaration order struct defspace_s *space; ///< storage for vars in scope symtabs + struct class_s *class; ///< owning class if ivar scope } symtab_t; const char *symtype_str (sy_type_e type) __attribute__((const)); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 8e2d458e1..50ab5dcd7 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1050,8 +1050,11 @@ class_find_ivar (class_t *class, int vis, const char *name) } ivar = symtab_lookup (class->ivars, name); if (ivar) { - if (ivar->visibility > (vis_t) vis) + if (ivar->visibility > (vis_t) vis + || (ivar->table->class != class + && ivar->visibility > vis_protected)) { goto access_error; + } return ivar; } error (0, "%s.%s does not exist", class->name, name); @@ -1180,6 +1183,7 @@ class_new_ivars (class_t *class) if (class->super_class) super_ivars = class->super_class->ivars; ivars = new_symtab (super_ivars, stab_local); + ivars->class = class; return ivars; } @@ -1756,6 +1760,15 @@ class_ivar_scope (class_type_t *class_type, symtab_t *parent) return symtab_flat_copy (class->ivars, parent); } +static expr_t * +class_dereference_ivar (symbol_t *sym, void *_self) +{ + expr_t *self = (expr_t *) _self; + + return field_expr (copy_expr (self), + new_symbol_expr (new_symbol (sym->name))); +} + void class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, symtab_t *param_scope) @@ -1769,8 +1782,9 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, if (!ivar_scope) return; self = symtab_lookup (param_scope, "self"); - if (!self) + if (!self) { internal_error (0, "I've lost my self!"); + } self_expr = new_symbol_expr (self); if (self->type != class_ptr) { debug (0, "class method scope"); @@ -1780,9 +1794,9 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, for (sym = ivar_scope->symbols; sym; sym = sym->next) { if (sym->sy_type != sy_var) continue; - sym->sy_type = sy_expr; - sym->s.expr = field_expr (copy_expr (self_expr), - new_symbol_expr (new_symbol (sym->name))); + sym->sy_type = sy_convert; + sym->s.convert.conv = class_dereference_ivar; + sym->s.convert.data = self_expr; } } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c384bcfe5..c82585674 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -109,6 +109,10 @@ convert_name (expr_t *e) //FIXME need a def return; } + if (sym->sy_type == sy_convert) { + new = sym->s.convert.conv (sym, sym->s.convert.data); + goto convert; + } if (sym->sy_type == sy_expr) { new = copy_expr (sym->s.expr); goto convert; diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 046f1c07b..f0d7daf4b 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -101,6 +101,8 @@ check_valid_lvalue (expr_t *expr) break; case sy_class: break; + case sy_convert: + break; } break; case ex_temp: diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 7af7f26b2..85c8a85ba 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -151,6 +151,9 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) } anonymous = s->type->t.symtab; for (as = anonymous->symbols; as; as = as->next) { + if (as->visibility == vis_anonymous || as->sy_type!= sy_var) { + continue; + } if (Hash_Find (symtab->tab, as->name)) { error (0, "ambiguous field `%s' in anonymous %s", as->name, su == 's' ? "struct" : "union"); @@ -158,6 +161,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) s->next = copy_symbol (as); s = s->next; s->s.offset += offset; + s->table = symtab; Hash_Add (symtab->tab, s); } } diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c index f94e8d71a..353e29142 100644 --- a/tools/qfcc/source/symtab.c +++ b/tools/qfcc/source/symtab.c @@ -59,6 +59,7 @@ static const char *sy_type_names[] = { "sy_expr", "sy_func", "sy_class", + "sy_convert", }; const char * @@ -165,6 +166,7 @@ symbol_t * copy_symbol (symbol_t *symbol) { symbol_t *sym = new_symbol (symbol->name); + sym->visibility = symbol->visibility; sym->type = symbol->type; sym->params = copy_params (symbol->params); sym->sy_type = symbol->sy_type;