diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 682bf59f5..07068ecb9 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -515,7 +515,11 @@ class_add_protocols (class_t *class, protocollist_t *protocols) for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; - copy_methods (methods, p->methods); + if (p->methods) { + copy_methods (methods, p->methods); + } else { + warning (0, "definition of protocol `%s' not found", p->name); + } if (p->protocols) class_add_protocols (class, p->protocols); } @@ -1356,7 +1360,7 @@ get_protocol (const char *name, int create) p = calloc (sizeof (protocol_t), 1); p->name = name; - p->methods = new_methodlist (); + p->methods = 0; p->class_type.type = ct_protocol; p->class_type.c.protocol = p; if (name) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 1bcd240c1..a7b353082 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -192,7 +192,7 @@ int yylex (void); %type overloaded_identifier %type identifier_list -%type selector reserved_word +%type protocol_name_list selector reserved_word %type optional_param_list unaryselector keyworddecl %type keywordselector %type methodproto methoddecl @@ -1443,6 +1443,7 @@ identifier obj_def : classdef { } | classdecl + | protocoldecl | protocoldef | { if (!current_class) PARSE_ERROR; } methoddef | END @@ -1570,17 +1571,18 @@ category_reference } ; - protocol_name : identifier { $$ = get_protocol ($1->name, 0); - if ($$) { - error (0, "redefinition of %s", $1->name); + if ($$ && $$->methods) { + error (0, "redefinition of protocol %s", $1->name); $$ = get_protocol (0, 1); - } else { + } + if (!$$) { $$ = get_protocol ($1->name, 1); } + $$->methods = new_methodlist (); current_class = &$$->class_type; } ; @@ -1673,18 +1675,33 @@ classdef | REFERENCE category_reference ';' { } ; +protocoldecl + : protocol + protocol_name_list ';' + { + while ($2) { + get_protocol ($2->name, 1); + $2 = $2->next; + } + } + ; + protocoldef - : PROTOCOL { $$ = current_class; } + : protocol protocol_name - protocolrefs { protocol_add_protocols ($3, $4); $$ = 0; } - methodprotolist { protocol_add_methods ($3, $6); } + protocolrefs { protocol_add_protocols ($2, $3); $$ = 0; } + methodprotolist { protocol_add_methods ($2, $5); } END { - current_class = $2; - (void) ($5); + current_class = $1; + (void) ($4); } ; +protocol + : PROTOCOL { $$ = current_class; } + ; + protocolrefs : /* emtpy */ { $$ = 0; } | LT { $$ = new_protocol_list (); } @@ -1870,6 +1887,10 @@ keywordselector | keywordselector keyworddecl { $2->next = $1; $$ = $2; } ; +protocol_name_list + : identifier + | protocol_name_list ',' identifier { $3->next = $1; $$ = $3; } + selector : NAME { $$ = $1; } | CLASS_NAME { $$ = $1; }