|
|
1.1 root 1: /* Implement classes and message passing for Objective C.
2: Copyright (C) 1992 Free Software Foundation, Inc.
3: Author: Steve Naroff.
4:
5: This file is part of GNU CC.
6:
7: GNU CC is free software; you can redistribute it and/or modify
8: it under the terms of the GNU General Public License as published by
9: the Free Software Foundation; either version 2, or (at your option)
10: any later version.
11:
12: GNU CC is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with GNU CC; see the file COPYING. If not, write to
19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20:
21: /*
22: * Purpose: This module implements the Objective-C 4.0 language.
23: *
24: * compatibility issues (with the Stepstone translator):
25: *
26: * - does not recognize the following 3.3 constructs.
27: * @requires, @classes, @messages, = (...)
28: * - methods with variable arguments must conform to ANSI standard.
29: * - tagged structure definitions that appear in BOTH the interface
30: * and implementation are not allowed.
31: * - public/private: all instance variables are public within the
32: * context of the implementation...I consider this to be a bug in
33: * the translator.
34: * - statically allocated objects are not supported. the user will
35: * receive an error if this service is requested.
36: *
37: * code generation `options':
38: *
1.1.1.2 ! root 39: * - OBJC_INT_SELECTORS, OBJC_NONUNIQUE_SELECTORS, NEXT_OBJC_RUNTIME
1.1 root 40: */
41:
42: #include <stdio.h>
43: #include "config.h"
44: #include "tree.h"
45: #include "c-tree.h"
46: #include "c-lex.h"
47: #include "flags.h"
48: #include "objc-actions.h"
49: #include "input.h"
50:
51: /* Define the special tree codes that we use. */
52:
53: /* Table indexed by tree code giving a string containing a character
54: classifying the tree code. Possibilities are
55: t, d, s, c, r, <, 1 and 2. See objc-tree.def for details. */
56:
57: #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
58:
59: char *objc_tree_code_type[] = {
60: "x",
61: #include "objc-tree.def"
62: };
63: #undef DEFTREECODE
64:
65: /* Table indexed by tree code giving number of expression
66: operands beyond the fixed part of the node structure.
67: Not used for types or decls. */
68:
69: #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
70:
71: int objc_tree_code_length[] = {
72: 0,
73: #include "objc-tree.def"
74: };
75: #undef DEFTREECODE
76:
77: /* Names of tree components.
78: Used for printing out the tree and error messages. */
79: #define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
80:
81: char *objc_tree_code_name[] = {
82: "@@dummy",
83: #include "objc-tree.def"
84: };
85: #undef DEFTREECODE
86:
87: /* for encode_method_def */
88: #include "rtl.h"
89:
90: #define OBJC_VERSION 2
91:
92: #define NULLT (tree) 0
93:
94: #define OBJC_ENCODE_INLINE_DEFS 0
95: #define OBJC_ENCODE_DONT_INLINE_DEFS 1
96:
97: /*** Private Interface (procedures) ***/
98:
99: /* code generation */
100:
101: static void synth_module_prologue ();
102: static char *build_module_descriptor ();
103: static tree init_module_descriptor ();
104: static void build_module_entry ();
105: static tree build_objc_method_call ();
106: static void build_message_selector_pool ();
107: static void build_selector_translation_table ();
108: static tree build_ivar_chain ();
109:
110: static tree build_ivar_template ();
111: static tree build_method_template ();
112: static tree build_private_template ();
113: static void build_class_template ();
114: static void build_category_template ();
115: static tree build_super_template ();
116:
117: static void synth_forward_declarations ();
118: static void generate_ivar_lists ();
119: static void generate_dispatch_tables ();
120: static void generate_shared_structures ();
121:
122: static tree build_msg_pool_reference ();
123: static tree init_selector ();
124: static tree build_keword_selector ();
125: static tree synth_id_with_class_suffix ();
126:
127: /* misc. bookkeeping */
128:
129: typedef struct hashedEntry *hash;
130: typedef struct hashedAttribute *attr;
131:
132: struct hashedAttribute {
133: attr next;
134: tree value;
135: };
136: struct hashedEntry {
137: attr list;
138: hash next;
139: tree key;
140: };
141: static void hash_init ();
142: static void hash_enter ();
143: static hash hash_lookup ();
144: static void hash_add_attr ();
145: static tree lookup_method ();
146: static tree lookup_instance_method_static ();
147: static tree lookup_class_method_static ();
148: static tree add_class ();
149: static int add_selector_reference ();
150: static void add_class_reference ();
151: static int add_objc_string ();
152:
153: /* type encoding */
154:
155: static void encode_aggregate ();
156: static void encode_bitfield ();
157: static void encode_type ();
158: static void encode_field_decl ();
159:
160: static void really_start_method ();
161: static int comp_method_with_proto ();
162: static int comp_proto_with_proto ();
163: static tree get_arg_type_list ();
164: static tree expr_last ();
165:
166: /* utilities for debugging and error diagnostics: */
167:
168: static void warn_with_method ();
169: static void error_with_method ();
170: static void error_with_ivar ();
171: static char *gen_method_decl ();
172: static char *gen_declaration ();
173: static char *gen_declarator ();
174: static int is_complex_decl ();
175: static void adorn_decl ();
176: static void dump_interfaces ();
177:
178: /*** Private Interface (data) ***/
179:
180: /* reserved tag definitions: */
181:
182: #define TYPE_ID "id"
183: #define TAG_OBJECT "objc_object"
184: #define TAG_CLASS "objc_class"
185: #define TAG_SUPER "objc_super"
186: #define TAG_SELECTOR "objc_selector"
187:
188: #define _TAG_CLASS "_objc_class"
189: #define _TAG_IVAR "_objc_ivar"
190: #define _TAG_IVAR_LIST "_objc_ivar_list"
191: #define _TAG_METHOD "_objc_method"
192: #define _TAG_METHOD_LIST "_objc_method_list"
193: #define _TAG_CATEGORY "_objc_category"
194: #define _TAG_MODULE "_objc_module"
195: #define _TAG_SYMTAB "_objc_symtab"
196: #define _TAG_SUPER "_objc_super"
197:
198: /* set by `continue_class ()' and checked by `is_public ()' */
199:
200: #define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC(record_type))
201: #define TYPED_OBJECT(type) \
202: (TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type))
203:
204: /* some commonly used instances of "identifier_node". */
205:
1.1.1.2 ! root 206: static tree self_id, _cmd_id;
1.1 root 207:
208: static tree self_decl, _msg_decl, _msgSuper_decl;
209: static tree objc_getClass_decl, objc_getMetaClass_decl;
210:
1.1.1.2 ! root 211: static tree super_type, selector_type, id_type, class_type;
1.1 root 212: static tree instance_type;
213:
214: static tree interface_chain = NULLT;
215:
216: /* chains to manage selectors that are referenced and defined in the module */
217:
218: static tree cls_ref_chain = NULLT; /* classes referenced */
219: static tree sel_ref_chain = NULLT; /* selectors referenced */
220: static tree sel_refdef_chain = NULLT; /* selectors references & defined */
221: static int max_selector_index; /* total # of selector referenced */
222:
223: /* hash tables to manage the global pool of method prototypes */
224:
225: static hash *nst_method_hash_list = 0;
226: static hash *cls_method_hash_list = 0;
227:
228: /* the following are used when compiling a class implementation.
229: *
230: * implementation_template will normally be an anInterface, however if
231: * none exists this will be equal to implementation_context...it is
232: * set in start_class.
233: */
234:
235: /* backend data declarations */
236:
237: static tree _OBJC_SYMBOLS_decl;
238: static tree _OBJC_INSTANCE_VARIABLES_decl, _OBJC_CLASS_VARIABLES_decl;
239: static tree _OBJC_INSTANCE_METHODS_decl, _OBJC_CLASS_METHODS_decl;
240: static tree _OBJC_CLASS_decl, _OBJC_METACLASS_decl;
241: #ifdef OBJC_NONUNIQUE_SELECTORS
242: static tree _OBJC_SELECTOR_REFERENCES_decl;
243: #endif
244: static tree _OBJC_MODULES_decl;
245: static tree _OBJC_STRINGS_decl;
246:
247: static tree implementation_context = NULLT,
248: implementation_template = NULLT;
249:
250: struct imp_entry {
251: struct imp_entry *next;
252: tree imp_context;
253: tree imp_template;
254: tree class_decl; /* _OBJC_CLASS_<my_name>; */
255: tree meta_decl; /* _OBJC_METACLASS_<my_name>; */
256: };
257: static struct imp_entry *imp_list = 0;
258: static int imp_count = 0; /* `@implementation' */
259: static int cat_count = 0; /* `@category' */
260:
261: static tree objc_class_template, objc_category_template, _PRIVATE_record;
262: static tree _clsSuper_ref, __clsSuper_ref;
263:
264: static tree objc_method_template, objc_ivar_template;
265: static tree objc_symtab_template, objc_module_template;
266: static tree objc_super_template, objc_object_reference;
267:
268: static tree objc_object_id, objc_class_id;
269: static tree _OBJC_SUPER_decl;
270:
271: static tree method_context = NULLT;
272: static int method_slot = 0; /* used by start_method_def */
273:
274: #define BUFSIZE 512
275:
276: static char *errbuf; /* a buffer for error diagnostics */
277: static char *utlbuf; /* a buffer for general utility */
278:
279: extern char *strcpy (), *strcat ();
280:
281: extern tree groktypename_in_parm_context ();
282:
283: extern struct obstack permanent_obstack, *current_obstack, *rtl_obstack;
284:
285: /* data imported from toplev.c */
286:
287: extern char *dump_base_name;
288:
289: /* Open and close the file for outputting class declarations, if requested. */
290:
291: int flag_gen_declaration = 0;
292:
293: FILE *gen_declaration_file;
294:
295: /* Warn if multiple methods are seen for the same selector, but with
296: different argument types. */
297:
298: int warn_selector = 0;
299:
300: void
301: lang_init ()
302: {
303: /* the beginning of the file is a new line; check for # */
304: /* With luck, we discover the real source file's name from that
305: and put it in input_filename. */
306: ungetc (check_newline (), finput);
307:
308: /* If gen_declaration desired, open the output file. */
309: if (flag_gen_declaration)
310: {
311: int dump_base_name_length = strlen (dump_base_name);
312: register char *dumpname = (char *) xmalloc (dump_base_name_length + 7);
313: strcpy (dumpname, dump_base_name);
314: strcat (dumpname, ".decl");
315: gen_declaration_file = fopen (dumpname, "w");
316: if (gen_declaration_file == 0)
317: pfatal_with_name (dumpname);
318: }
319:
320: if (doing_objc_thang)
321: init_objc ();
322: }
323:
324: void
325: objc_finish ()
326: {
327: if (doing_objc_thang)
328: finish_objc (); /* Objective-C finalization */
329:
330: if (gen_declaration_file)
331: fclose (gen_declaration_file);
332: }
333:
334: void
335: lang_finish ()
336: {
337: }
338:
339: int
340: lang_decode_option (p)
341: char *p;
342: {
343: if (!strcmp (p, "-lang-objc"))
344: doing_objc_thang = 1;
345: else if (!strcmp (p, "-gen-decls"))
346: flag_gen_declaration = 1;
347: else if (!strcmp (p, "-Wselector"))
348: warn_selector = 1;
349: else if (!strcmp (p, "-Wno-selector"))
350: warn_selector = 0;
351: else
352: return c_decode_option (p);
353:
354: return 1;
355: }
356:
357: static tree
358: define_decl (declarator, declspecs)
359: tree declarator;
360: tree declspecs;
361: {
362: tree decl = start_decl (declarator, declspecs, 0);
363: finish_decl (decl, NULLT, NULLT);
364: return decl;
365: }
366:
367: /*
368: * rules for statically typed objects...called from `c-typeck.comptypes'.
369: *
370: * an assignment of the form `a' = `b' is permitted if:
371: *
372: * - `a' is of type "id".
373: * - `a' and `b' are the same class type.
374: * - `a' and `b' are of class types A and B such that B is a descendant
375: * of A.
376: */
377:
378: int
379: maybe_objc_comptypes (lhs, rhs)
380: tree lhs, rhs;
381: {
382: if (doing_objc_thang)
383: return objc_comptypes (lhs, rhs);
384: return 0;
385: }
386:
387: int
388: objc_comptypes (lhs, rhs)
389: tree lhs;
390: tree rhs;
391: {
392: /* `id' = `<class> *', `<class> *' = `id' */
393:
394: if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs))
395: || (TYPED_OBJECT (lhs) && TYPE_NAME (rhs) == objc_object_id))
396: return 1;
397:
398: /* `id' = `Class', `Class' = `id' */
399:
400:
401: else if ((TYPE_NAME (lhs) == objc_object_id &&
402: TYPE_NAME (rhs) == objc_class_id) ||
403: (TYPE_NAME (lhs) == objc_class_id &&
404: TYPE_NAME (rhs) == objc_object_id))
405: return 1;
406:
407: /* `<class> *' = `<class> *' */
408:
409: else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs))
410: {
411: tree lname = TYPE_NAME (lhs), rname = TYPE_NAME (rhs);
412:
413: if (lname == rname)
414: return 1;
415: else
416: {
417: /* if the left hand side is a super class of the right hand side,
418: allow it...
419: */
420: tree rinter = lookup_interface (rname);
421:
422: while (rinter)
423: {
424: if (lname == CLASS_SUPER_NAME (rinter))
425: return 1;
426:
427: rinter = lookup_interface (CLASS_SUPER_NAME (rinter));
428: }
429:
430: return 0;
431: }
432: }
433: else
434: return 0;
435: }
436:
437: /* Called from c-decl.c before all calls to rest_of_decl_compilation. */
438:
439: void
440: maybe_objc_check_decl (decl)
441: tree decl;
442: {
443: if (doing_objc_thang)
444: objc_check_decl (decl);
445: }
446:
447: void
448: objc_check_decl (decl)
449: tree decl;
450: {
451: tree type = TREE_TYPE (decl);
452: static int alreadyWarned = 0;
453:
454: if (TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type))
455: {
456: if (!alreadyWarned)
457: {
458: error ("GNU compiler does not support statically allocated objects");
459: alreadyWarned = 1;
460: }
461: error_with_decl (decl, "`%s' cannot be statically allocated");
462: }
463: }
464:
465: /* implement static typing. at this point, we know we have an interface... */
466:
467: tree
468: get_static_reference (interface)
469: tree interface;
470: {
471: return xref_tag (RECORD_TYPE, CLASS_NAME (interface));
472: }
473:
1.1.1.2 ! root 474: /* Create and push a decl for a built-in external variable or field NAME.
! 475: CODE says which.
! 476: TYPE is its data type. */
! 477:
! 478: static tree
! 479: create_builtin_decl (code, type, name)
! 480: enum tree_code code;
! 481: char *name;
! 482: tree type;
! 483: {
! 484: tree decl = build_decl (code, get_identifier (name), type);
! 485: if (code == VAR_DECL)
! 486: {
! 487: TREE_EXTERNAL (decl) = 1;
! 488: TREE_PUBLIC (decl) = 1;
! 489: make_decl_rtl (decl, 0, 1);
! 490: pushdecl (decl);
! 491: }
! 492: return decl;
! 493: }
! 494:
1.1 root 495: /*
496: * purpose: "play" parser, creating/installing representations
497: * of the declarations that are required by Objective-C.
498: *
499: * model:
500: *
501: * type_spec--------->sc_spec
502: * (tree_list) (tree_list)
503: * | |
504: * | |
505: * identifier_node identifier_node
506: */
507: static void
508: synth_module_prologue ()
509: {
1.1.1.2 ! root 510: tree expr_decl, temp_type;
1.1 root 511:
512: /* defined in `objc.h' */
513: objc_object_id = get_identifier (TAG_OBJECT);
514:
515: objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id);
516:
1.1.1.2 ! root 517: id_type = build_pointer_type (objc_object_reference);
1.1 root 518:
519: objc_class_id = get_identifier (TAG_CLASS);
520:
1.1.1.2 ! root 521: class_type = build_pointer_type (xref_tag (RECORD_TYPE, objc_class_id));
! 522:
! 523: /* Declare type of selector-objects that represent an operation name. */
1.1 root 524:
525: #ifdef OBJC_INT_SELECTORS
526: /* `unsigned int' */
1.1.1.2 ! root 527: selector_type = unsigned_type_node;
1.1 root 528: #else
529: /* `struct objc_selector *' */
1.1.1.2 ! root 530: selector_type
! 531: = build_pointer_type (xref_tag (RECORD_TYPE,
! 532: get_identifier (TAG_SELECTOR)));
1.1 root 533: #endif /* not OBJC_INT_SELECTORS */
534:
535: /* struct objc_object *objc_msgSend (id, SEL, ...); */
536:
1.1.1.2 ! root 537: temp_type
! 538: = build_function_type (id_type,
! 539: tree_cons (NULL_TREE, id_type,
! 540: tree_cons (NULLT, selector_type, NULLT)));
! 541:
! 542: _msg_decl = builtin_function ("objc_msgSend", temp_type, NOT_BUILT_IN, 0);
! 543:
! 544: /* struct objc_object *objc_msgSendSuper (void *, SEL, ...); */
! 545:
! 546: temp_type
! 547: = build_function_type (id_type,
! 548: tree_cons (NULL_TREE, ptr_type_node,
! 549: tree_cons (NULLT, selector_type, NULLT)));
1.1 root 550:
1.1.1.2 ! root 551: _msgSuper_decl = builtin_function ("objc_msgSendSuper",
! 552: temp_type, NOT_BUILT_IN, 0);
1.1 root 553:
554: /* id objc_getClass (); */
1.1.1.2 ! root 555:
! 556: temp_type = build_function_type (id_type, NULLT);
1.1 root 557:
1.1.1.2 ! root 558: objc_getClass_decl
! 559: = builtin_function ("objc_getClass", temp_type, NOT_BUILT_IN, 0);
1.1 root 560:
561: /* id objc_getMetaClass (); */
562:
1.1.1.2 ! root 563: objc_getMetaClass_decl
! 564: = builtin_function ("objc_getMetaClass", temp_type, NOT_BUILT_IN, 0);
1.1 root 565:
566: /* extern SEL _OBJC_SELECTOR_REFERENCES[]; */
567:
1.1.1.2 ! root 568: #ifdef OBJC_NONUNIQUE_SELECTORS
! 569: _OBJC_SELECTOR_REFERENCES_decl
! 570: = create_builtin_decl (VAR_DECL, build_array_type (selector_type, NULLT),
! 571: "_OBJC_SELECTOR_REFERENCES");
1.1 root 572: #endif
573: }
574:
575: /*
576: * custom "build_string ()" which sets TREE_TYPE!
577: */
578: static tree
579: my_build_string (len, str)
580: int len;
581: char *str;
582: {
583: int wide_flag = 0;
584: tree aString = build_string (len, str);
585: /*
586: * some code from "combine_strings ()", which is local to c-parse.y.
587: */
588: if (TREE_TYPE (aString) == int_array_type_node)
589: wide_flag = 1;
590:
591: TREE_TYPE (aString) =
592: build_array_type (wide_flag ? integer_type_node : char_type_node,
593: build_index_type (build_int_2 (len - 1, 0)));
594:
595: TREE_CONSTANT (aString) = 1; /* puts string in the ".text" segment */
596: TREE_STATIC (aString) = 1;
597:
598: return aString;
599: }
1.1.1.2 ! root 600:
! 601: /* Take care of defining and initializing _OBJC_SYMBOLS. */
! 602:
! 603: /* Predefine the following data type:
! 604:
! 605: struct _objc_symtab {
! 606: long sel_ref_cnt;
! 607: SEL *refs;
! 608: short cls_def_cnt;
! 609: short cat_def_cnt;
! 610: void *defs[cls_def_cnt + cat_def_cnt];
! 611: }; */
1.1 root 612:
613: static void
614: build_objc_symtab_template ()
615: {
1.1.1.2 ! root 616: tree field_decl, field_decl_chain, index;
1.1 root 617:
618: objc_symtab_template = start_struct (RECORD_TYPE, get_identifier (_TAG_SYMTAB));
619:
620: /* long sel_ref_cnt; */
621:
1.1.1.2 ! root 622: field_decl = create_builtin_decl (FIELD_DECL,
! 623: long_integer_type_node,
! 624: "sel_ref_cnt");
1.1 root 625: field_decl_chain = field_decl;
626:
1.1.1.2 ! root 627: /* SEL *refs; */
1.1 root 628:
1.1.1.2 ! root 629: field_decl = create_builtin_decl (FIELD_DECL,
! 630: build_pointer_type (selector_type),
! 631: "refs");
1.1 root 632: chainon (field_decl_chain, field_decl);
633:
634: /* short cls_def_cnt; */
635:
1.1.1.2 ! root 636: field_decl = create_builtin_decl (FIELD_DECL,
! 637: short_integer_type_node,
! 638: "cls_def_cnt");
1.1 root 639: chainon (field_decl_chain, field_decl);
640:
641: /* short cat_def_cnt; */
642:
1.1.1.2 ! root 643: field_decl = create_builtin_decl (FIELD_DECL,
! 644: short_integer_type_node,
! 645: "cat_def_cnt");
1.1 root 646: chainon (field_decl_chain, field_decl);
647:
648: /* void *defs[cls_def_cnt + cat_def_cnt]; */
649:
1.1.1.2 ! root 650: index = build_index_type (build_int_2 (imp_count + cat_count - 1, 0));
! 651: field_decl = create_builtin_decl (FIELD_DECL,
! 652: build_array_type (ptr_type_node, index),
! 653: "defs");
1.1 root 654: chainon (field_decl_chain, field_decl);
655:
656: finish_struct (objc_symtab_template, field_decl_chain);
657: }
658:
1.1.1.2 ! root 659: /* Create the initial value for the `defs' field of _objc_symtab.
! 660: This is a CONSTRUCTOR. */
! 661:
1.1 root 662: static tree
663: init_def_list ()
664: {
665: tree expr, initlist = NULLT;
666: struct imp_entry *impent;
667:
668: if (imp_count)
669: for (impent = imp_list; impent; impent = impent->next)
670: {
671: if (TREE_CODE (impent->imp_context) == IMPLEMENTATION_TYPE)
672: {
673: expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0);
674: initlist = tree_cons (NULLT, expr, initlist);
675: }
676: }
677:
678: if (cat_count)
679: for (impent = imp_list; impent; impent = impent->next)
680: {
681: if (TREE_CODE (impent->imp_context) == CATEGORY_TYPE)
682: {
683: expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0);
684: initlist = tree_cons (NULLT, expr, initlist);
685: }
686: }
687: return build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
688: }
689:
1.1.1.2 ! root 690: /* Construct the initial value for all of _objc_symtab. */
! 691:
1.1 root 692: static tree
693: init_objc_symtab ()
694: {
695: tree initlist;
696:
697: /* sel_ref_cnt = { ..., 5, ... } */
698:
699: if (sel_ref_chain)
700: initlist = build_tree_list (NULLT, build_int_2 (max_selector_index, 0));
701: else
702: initlist = build_tree_list (NULLT, build_int_2 (0, 0));
703:
704: /* refs = { ..., _OBJC_SELECTOR_REFERENCES, ... } */
705:
706: #ifndef OBJC_NONUNIQUE_SELECTORS
707: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
708: #else
709: if (sel_ref_chain)
710: initlist = tree_cons (NULLT, _OBJC_SELECTOR_REFERENCES_decl, initlist);
711: else
712: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
713: #endif
714:
715: /* cls_def_cnt = { ..., 5, ... } */
716:
717: initlist = tree_cons (NULLT, build_int_2 (imp_count, 0), initlist);
718:
719: /* cat_def_cnt = { ..., 5, ... } */
720:
721: initlist = tree_cons (NULLT, build_int_2 (cat_count, 0), initlist);
722:
723: /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
724:
725: if (imp_count || cat_count)
726: initlist = tree_cons (NULLT, init_def_list (), initlist);
727:
728: return build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
729: }
730:
1.1.1.2 ! root 731: /* Push forward-declarations of all the categories
! 732: so that init_def_list can use them in a CONSTRUCTOR. */
! 733:
1.1 root 734: static void
735: forward_declare_categories ()
736: {
737: struct imp_entry *impent;
738: tree sav = implementation_context;
739: for (impent = imp_list; impent; impent = impent->next)
740: {
741: if (TREE_CODE (impent->imp_context) == CATEGORY_TYPE)
742: {
1.1.1.2 ! root 743: /* Set an invisible arg to synth_id_with_class_suffix. */
1.1 root 744: implementation_context = impent->imp_context;
1.1.1.2 ! root 745: impent->class_decl
! 746: = create_builtin_decl (VAR_DECL, objc_category_template,
! 747: synth_id_with_class_suffix ("_OBJC_CATEGORY"));
1.1 root 748: }
749: }
750: implementation_context = sav;
751: }
752:
1.1.1.2 ! root 753: /* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab'
! 754: and initialized appropriately. */
! 755:
1.1 root 756: static void
757: generate_objc_symtab_decl ()
758: {
759: tree sc_spec;
760:
761: if (!objc_category_template)
762: build_category_template ();
763:
764: /* forward declare categories */
765: if (cat_count)
766: forward_declare_categories ();
767:
768: if (!objc_symtab_template)
769: build_objc_symtab_template ();
770:
771: sc_spec = build_tree_list (NULLT, ridpointers[(int) RID_STATIC]);
772:
773: _OBJC_SYMBOLS_decl = start_decl (get_identifier ("_OBJC_SYMBOLS"),
774: tree_cons (NULLT, objc_symtab_template, sc_spec), 1);
775:
776: finish_decl (_OBJC_SYMBOLS_decl, init_objc_symtab (), NULLT);
777: }
1.1.1.2 ! root 778:
1.1 root 779: /*
780: * tree_node------->tree_node----->...
781: * | |
782: * | (value) | (value)
783: * | |
784: * expr expr
785: */
786: static tree
787: init_module_descriptor ()
788: {
789: tree initlist, expr;
790:
791: /* version = { 1, ... } */
792:
793: expr = build_int_2 (OBJC_VERSION, 0);
794: initlist = build_tree_list (NULLT, expr);
795:
796: /* size = { ..., sizeof (struct objc_module), ... } */
797:
798: expr = build_int_2 (TREE_INT_CST_LOW (TYPE_SIZE (objc_module_template)) /
799: BITS_PER_UNIT, 0);
800: initlist = tree_cons (NULLT, expr, initlist);
801:
802: /* name = { ..., "foo.m", ... } */
803:
804: expr = build_msg_pool_reference (
805: add_objc_string (get_identifier (input_filename)));
806: initlist = tree_cons (NULLT, expr, initlist);
807:
808: /* symtab = { ..., _OBJC_SYMBOLS, ... } */
809:
810: if (_OBJC_SYMBOLS_decl)
811: expr = build_unary_op (ADDR_EXPR, _OBJC_SYMBOLS_decl, 0);
812: else
813: expr = build_int_2 (0, 0);
814: initlist = tree_cons (NULLT, expr, initlist);
815:
816: return build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
817: }
818:
819: /* Write out the data structures to describe Objective C classes defined.
820: If appropriate, compile and output a setup function to initialize them.
821: Return a string which is the name of a function to call to initialize
822: the Objective C data structures for this file (and perhaps for other files
823: also). */
824:
825: static char *
826: build_module_descriptor ()
827: {
828: tree decl_specs, field_decl, field_decl_chain;
829:
830: objc_module_template = start_struct (RECORD_TYPE, get_identifier (_TAG_MODULE));
831:
832: /* long version; */
833:
834: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_LONG]);
835: field_decl = get_identifier ("version");
836: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
837: field_decl_chain = field_decl;
838:
839: /* long size; */
840:
841: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_LONG]);
842: field_decl = get_identifier ("size");
843: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
844: chainon (field_decl_chain, field_decl);
845:
846: /* char *name; */
847:
848: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_CHAR]);
849: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("name"));
850: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
851: chainon (field_decl_chain, field_decl);
852:
853: /* struct objc_symtab *symtab; */
854:
855: decl_specs = get_identifier (_TAG_SYMTAB);
856: decl_specs = build_tree_list (NULLT, xref_tag (RECORD_TYPE, decl_specs));
857: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("symtab"));
858: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
859: chainon (field_decl_chain, field_decl);
860:
861: finish_struct (objc_module_template, field_decl_chain);
862:
863: /* create an instance of "objc_module" */
864:
865: decl_specs = tree_cons (NULLT, objc_module_template,
866: build_tree_list (NULLT, ridpointers[(int) RID_STATIC]));
867:
868: _OBJC_MODULES_decl = start_decl (get_identifier ("_OBJC_MODULES"),
869: decl_specs, 1);
870:
871: finish_decl (_OBJC_MODULES_decl, init_module_descriptor (), NULLT);
872:
873: /* Mark the decl as used to avoid "defined but not used" warning. */
874: TREE_USED (_OBJC_MODULES_decl) = 1;
875:
876: /* Generate a constructor call for the module descriptor.
877: This code was generated by reading the grammar rules
878: of c-parse.y; Therefore, it may not be the most efficient
879: way of generating the requisite code. */
880: #ifndef NEXT_OBJC_RUNTIME
881: {
882: tree parms, function_decl, decelerator, void_list_node;
883: tree function_type;
884: char *buf;
885: char *global_object_name = 0;
886: tree t;
887:
888: /* Use a global object (which is already required to be unique over
889: the program) rather than the file name (which imposes extra
890: constraints). -- [email protected], 10 Jan 1990. */
891:
892: /* Find the name of some global object defined in this file. */
893: for (t = getdecls (); t; t = TREE_CHAIN (t))
894: if (TREE_PUBLIC (t) && !TREE_EXTERNAL (t) && DECL_INITIAL (t) != 0)
895: {
896: global_object_name = IDENTIFIER_POINTER (DECL_NAME (t));
897: break;
898: }
899:
900: /* If none, use the name of the file. */
901: if (!global_object_name)
902: {
903: char *p, *q;
904: global_object_name
905: = (char *) alloca (strlen (main_input_filename) + 1);
906:
907: p = main_input_filename;
908: q = global_object_name;
909:
910: /* Replace any weird characters in the file name. */
911: for (; *p; p++)
912: if (! ((*p >= '0' && *p <= '9')
913: || (*p >= 'A' && *p <= 'Z')
914: || (*p >= 'a' && *p <= 'z')))
915: *q++ = '_';
916: else
917: *q++ = *p;
918: *q = 0;
919: }
920:
921: /* Make the constructor name from the name we have found. */
922: buf = (char *) xmalloc (sizeof (CONSTRUCTOR_NAME_FORMAT)
923: + strlen (global_object_name));
924: sprintf (buf, CONSTRUCTOR_NAME_FORMAT, global_object_name);
925:
926: /* Declare void __objc_execClass (void*); */
927:
928: void_list_node = build_tree_list (NULL_TREE, void_type_node);
929: function_type
930: = build_function_type (void_type_node,
931: tree_cons (NULL_TREE, ptr_type_node,
932: void_list_node));
933: function_decl = build_decl (FUNCTION_DECL,
934: get_identifier ("__objc_execClass"),
935: function_type);
936: TREE_EXTERNAL (function_decl) = 1;
937: TREE_PUBLIC (function_decl) = 1;
938: pushdecl (function_decl);
939: rest_of_decl_compilation (function_decl, 0, 0, 0);
940:
941: parms
942: = build_tree_list (NULLT,
943: build_unary_op (ADDR_EXPR, _OBJC_MODULES_decl, 0));
944: decelerator = build_function_call (function_decl, parms);
945:
946: /* void __objc_file_init () {objc_execClass(&L_OBJC_MODULES);} */
947:
948: start_function (void_list_node,
949: build_parse_node (CALL_EXPR, get_identifier (buf),
950: /* This has the format of the output
951: of get_parm_info. */
952: tree_cons (NULL_TREE, NULL_TREE,
953: void_list_node),
954: NULL_TREE),
955: 0, 0);
956: #if 0 /* This should be turned back on later
957: for the systems where collect is not needed. */
958: /* Make these functions nonglobal
959: so each file can use the same name. */
960: TREE_PUBLIC (current_function_decl) = 0;
961: #endif
962: TREE_USED (current_function_decl) = 1;
963: store_parm_decls ();
964:
965: assemble_external (function_decl);
966: c_expand_expr_stmt (decelerator);
967:
968: finish_function (0);
969:
970: /* Return the name of the constructor function. */
971: return buf;
972: }
973: #else /* NEXT_OBJC_RUNTIME */
974: return 0;
975: #endif /* NEXT_OBJC_RUNTIME */
976: }
977:
978: /* extern const char _OBJC_STRINGS[]; */
979:
980: static void
981: generate_forward_declaration_to_string_table ()
982: {
983: tree sc_spec, decl_specs, expr_decl;
984:
985: sc_spec = tree_cons (NULLT, ridpointers[(int) RID_EXTERN], NULLT);
986: decl_specs = tree_cons (NULLT, ridpointers[(int) RID_CHAR], sc_spec);
987:
988: expr_decl = build_nt (ARRAY_REF, get_identifier ("_OBJC_STRINGS"), NULLT);
989:
990: _OBJC_STRINGS_decl = define_decl (expr_decl, decl_specs);
991: }
992:
993: /* static char _OBJC_STRINGS[] = "..."; */
994:
995: static void
996: build_message_selector_pool ()
997: {
998: tree sc_spec, decl_specs, expr_decl;
999: tree chain, string_expr;
1000: int goolengthtmp = 0, msg_pool_size = 0;
1001: char *string_goo;
1002:
1003: sc_spec = tree_cons (NULLT, ridpointers[(int) RID_STATIC], NULLT);
1004: decl_specs = tree_cons (NULLT, ridpointers[(int) RID_CHAR], sc_spec);
1005:
1006: expr_decl = build_nt (ARRAY_REF, get_identifier ("_OBJC_STRINGS"), NULLT);
1007:
1008: _OBJC_STRINGS_decl = start_decl (expr_decl, decl_specs, 1);
1009:
1010: for (chain = sel_refdef_chain; chain; chain = TREE_CHAIN (chain))
1011: msg_pool_size += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
1012:
1013: msg_pool_size++;
1014:
1015: string_goo = (char *)xmalloc (msg_pool_size);
1016: bzero (string_goo, msg_pool_size);
1017:
1018: for (chain = sel_refdef_chain; chain; chain = TREE_CHAIN (chain))
1019: {
1020: strcpy (string_goo + goolengthtmp, IDENTIFIER_POINTER (TREE_VALUE (chain)));
1021: goolengthtmp += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
1022: }
1023:
1024: string_expr = my_build_string (msg_pool_size, string_goo);
1025:
1026: finish_decl (_OBJC_STRINGS_decl, string_expr, NULLT);
1027: }
1028:
1029: /*
1030: * synthesize the following expr: (char *)&_OBJC_STRINGS[<offset>]
1031: *
1032: * the cast stops the compiler from issuing the following message:
1033: *
1034: * grok.m: warning: initialization of non-const * pointer from const *
1035: * grok.m: warning: initialization between incompatible pointer types
1036: */
1037: static tree
1038: build_msg_pool_reference (offset)
1039: int offset;
1040: {
1041: tree expr = build_int_2 (offset, 0);
1042: tree cast;
1043:
1044: expr = build_array_ref (_OBJC_STRINGS_decl, expr);
1045: expr = build_unary_op (ADDR_EXPR, expr, 0);
1046:
1047: cast = build_tree_list (build_tree_list (NULLT, ridpointers[(int) RID_CHAR]),
1048: build1 (INDIRECT_REF, NULLT, NULLT));
1049: TREE_TYPE (expr) = groktypename (cast);
1050: return expr;
1051: }
1052:
1053: #ifndef OBJC_NONUNIQUE_SELECTORS
1054: static tree
1055: build_selector_reference (idx)
1056: int idx;
1057: {
1058: tree ref, decl, name, ident;
1059: char buf[256];
1060: struct obstack *save_current_obstack = current_obstack;
1061: struct obstack *save_rtl_obstack = rtl_obstack;
1062:
1063: sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", idx);
1064:
1065: /* new stuff */
1066: rtl_obstack = current_obstack = &permanent_obstack;
1067: ident = get_identifier (buf);
1068:
1069: if (IDENTIFIER_GLOBAL_VALUE (ident))
1070: decl = IDENTIFIER_GLOBAL_VALUE (ident); /* set by pushdecl() */
1071: else
1072: {
1.1.1.2 ! root 1073: decl = build_decl (VAR_DECL, ident, selector_type);
1.1 root 1074: TREE_EXTERNAL (decl) = 1;
1075: TREE_PUBLIC (decl) = 1;
1076: TREE_USED (decl) = 1;
1077:
1078: make_decl_rtl (decl, 0, 1); /* usually called from `rest_of_decl_compilation' */
1079: pushdecl_top_level (decl); /* our `extended/custom' pushdecl in c-decl.c */
1080: }
1081: current_obstack = save_current_obstack;
1082: rtl_obstack = save_rtl_obstack;
1083:
1084: return decl;
1085: }
1086: #endif
1087:
1088: static tree
1089: init_selector (offset)
1090: int offset;
1091: {
1092: tree expr = build_msg_pool_reference (offset);
1.1.1.2 ! root 1093: TREE_TYPE (expr) = selector_type; /* cast */
1.1 root 1094: return expr;
1095: }
1096:
1097: static void
1098: build_selector_translation_table ()
1099: {
1100: tree sc_spec, decl_specs, expr_decl;
1101: tree chain, initlist = NULLT;
1102: int offset = 0;
1103: #ifndef OBJC_NONUNIQUE_SELECTORS
1104: tree decl, var_decl;
1105: int idx = 0;
1106: char buf[256];
1.1.1.2 ! root 1107: #else
! 1108: /* The corresponding pop_obstacks is in finish_decl,
! 1109: called at the end of this function. */
! 1110: push_obstacks_nochange ();
1.1 root 1111: #endif
1112:
1113: for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
1114: {
1115: tree expr;
1116:
1117: #ifndef OBJC_NONUNIQUE_SELECTORS
1118: sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", idx);
1.1.1.2 ! root 1119: sc_spec = build_tree_list (NULLT, ridpointers[(int) RID_STATIC]);
1.1 root 1120:
1.1.1.2 ! root 1121: /* static SEL _OBJC_SELECTOR_REFERENCES_n = ...; */
! 1122: decl_specs = tree_cons (NULLT, selector_type, sc_spec);
1.1 root 1123: var_decl = get_identifier (buf);
1124:
1125: /* the `decl' that is returned from start_decl is the one that we
1126: * forward declared in `build_selector_reference()'
1127: */
1128: decl = start_decl (var_decl, decl_specs, 1);
1129: #endif
1130:
1131: expr = init_selector (offset);
1132:
1133: /* add one for the '\0' character */
1134: offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
1135:
1136: #ifndef OBJC_NONUNIQUE_SELECTORS
1137: finish_decl (decl, expr, NULLT);
1138: idx++;
1139: #else
1140: initlist = tree_cons (NULLT, expr, initlist);
1141: #endif
1142: }
1143:
1144: #ifdef OBJC_NONUNIQUE_SELECTORS
1.1.1.2 ! root 1145: DECL_INITIAL (_OBJC_SELECTOR_REFERENCES_decl) = (tree) 1;
1.1 root 1146: initlist = build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
1147: finish_decl (_OBJC_SELECTOR_REFERENCES_decl, initlist, NULLT);
1148: #endif
1149: }
1150:
1151: static void
1152: add_class_reference (ident)
1153: tree ident;
1154: {
1155: tree chain;
1156:
1157: if (chain = cls_ref_chain)
1158: {
1159: tree tail;
1160: do
1161: {
1162: if (ident == TREE_VALUE (chain))
1163: return;
1164:
1165: tail = chain;
1166: chain = TREE_CHAIN (chain);
1167: }
1168: while (chain);
1169:
1170: /* append to the end of the list */
1171: TREE_CHAIN (tail) = perm_tree_cons (NULLT, ident, NULLT);
1172: }
1173: else
1174: cls_ref_chain = perm_tree_cons (NULLT, ident, NULLT);
1175: }
1176:
1177: /*
1178: * sel_ref_chain is a list whose "value" fields will be instances of
1179: * identifier_node that represent the selector.
1180: */
1181: static int
1182: add_selector_reference (ident)
1183: tree ident;
1184: {
1185: tree chain;
1186: int index = 0;
1187:
1188: /* this adds it to sel_refdef_chain, the global pool of selectors */
1189: add_objc_string (ident);
1190:
1191: if (chain = sel_ref_chain)
1192: {
1193: tree tail;
1194: do
1195: {
1196: if (ident == TREE_VALUE (chain))
1197: return index;
1198:
1199: index++;
1200: tail = chain;
1201: chain = TREE_CHAIN (chain);
1202: }
1203: while (chain);
1204:
1205: /* append to the end of the list */
1206: TREE_CHAIN (tail) = perm_tree_cons (NULLT, ident, NULLT);
1207: }
1208: else
1209: sel_ref_chain = perm_tree_cons (NULLT, ident, NULLT);
1210:
1211: max_selector_index++;
1212: return index;
1213: }
1214:
1215: /*
1216: * sel_refdef_chain is a list whose "value" fields will be instances of
1217: * identifier_node that represent the selector. It returns the offset of
1218: * the selector from the beginning of the _OBJC_STRINGS pool. This offset
1219: * is typically used by "init_selector ()" during code generation.
1220: */
1221: static int
1222: add_objc_string (ident)
1223: tree ident;
1224: {
1225: tree chain;
1226: int offset = 0;
1227:
1228: if (chain = sel_refdef_chain)
1229: {
1230: tree tail;
1231: do
1232: {
1233: if (ident == TREE_VALUE (chain))
1234: return offset;
1235:
1236: /* add one for the '\0' character */
1237: offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
1238: tail = chain;
1239: chain = TREE_CHAIN (chain);
1240: }
1241: while (chain);
1242:
1243: /* append to the end of the list */
1244: TREE_CHAIN (tail) = perm_tree_cons (NULLT, ident, NULLT);
1245: }
1246: else
1247: sel_refdef_chain = perm_tree_cons (NULLT, ident, NULLT);
1248:
1249: return offset;
1250: }
1251:
1252: tree
1253: lookup_interface (ident)
1254: tree ident;
1255: {
1256: tree chain;
1257:
1258: for (chain = interface_chain; chain; chain = TREE_CHAIN (chain))
1259: {
1260: if (ident == CLASS_NAME (chain))
1261: return chain;
1262: }
1263: return NULLT;
1264: }
1265:
1266: static tree
1267: objc_copy_list (list, head)
1268: tree list;
1269: tree *head;
1270: {
1271: tree newlist = NULL_TREE, tail = NULL_TREE;
1272:
1273: while (list)
1274: {
1275: tail = copy_node (list);
1276:
1277: /* the following statement fixes a bug when inheriting instance
1278: variables that are declared to be bitfields. finish_struct () expects
1279: to find the width of the bitfield in DECL_INITIAL (), which it
1280: nulls out after processing the decl of the super class...rather
1281: than change the way finish_struct () works (which is risky),
1282: I create the situation it expects...s.naroff (7/23/89).
1283: */
1284: if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0)
1285: DECL_INITIAL (tail) = build_int_2 (DECL_FRAME_SIZE (tail), 0);
1286:
1287: newlist = chainon (newlist, tail);
1288: list = TREE_CHAIN (list);
1289: }
1290: *head = newlist;
1291: return tail;
1292: }
1293:
1294: /* used by:
1295: * build_private_template (), get_class_ivars (), and get_static_reference ().
1296: */
1297: static tree
1298: build_ivar_chain (interface)
1299: tree interface;
1300: {
1301: tree my_name, super_name, ivar_chain;
1302:
1303: my_name = CLASS_NAME (interface);
1304: super_name = CLASS_SUPER_NAME (interface);
1305:
1306: /* "leaf" ivars never get copied...there is no reason to. */
1307: ivar_chain = CLASS_IVARS (interface);
1308:
1309: while (super_name)
1310: {
1311: tree op1;
1312: tree super_interface = lookup_interface (super_name);
1313:
1314: if (!super_interface)
1315: {
1316: /* fatal did not work with 2 args...should fix */
1317: error ("Cannot find interface declaration for `%s', superclass of `%s'",
1318: IDENTIFIER_POINTER (super_name), IDENTIFIER_POINTER (my_name));
1319: exit (34);
1320: }
1321: if (super_interface == interface)
1322: {
1323: fatal ("Circular inheritance in interface declaration for `%s'",
1324: IDENTIFIER_POINTER (super_name));
1325: }
1326: interface = super_interface;
1327: my_name = CLASS_NAME (interface);
1328: super_name = CLASS_SUPER_NAME (interface);
1329:
1330: op1 = CLASS_IVARS (interface);
1331: if (op1)
1332: {
1333: tree head, tail = objc_copy_list (op1, &head);
1334:
1335: /* prepend super class ivars...make a copy of the list, we
1336: * do not want to alter the original.
1337: */
1338: TREE_CHAIN (tail) = ivar_chain;
1339: ivar_chain = head;
1340: }
1341: }
1342: return ivar_chain;
1343: }
1344:
1345: /*
1346: * struct <classname> {
1347: * struct objc_class *isa;
1348: * ...
1349: * };
1350: */
1351: static tree
1352: build_private_template (class)
1353: tree class;
1354: {
1355: tree ivar_context;
1356:
1357: if (CLASS_STATIC_TEMPLATE (class))
1358: {
1359: _PRIVATE_record = CLASS_STATIC_TEMPLATE (class);
1360: ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class));
1361: }
1362: else
1363: {
1364: _PRIVATE_record = start_struct (RECORD_TYPE, CLASS_NAME (class));
1365:
1366: ivar_context = build_ivar_chain (class);
1367:
1368: finish_struct (_PRIVATE_record, ivar_context);
1369:
1370: CLASS_STATIC_TEMPLATE (class) = _PRIVATE_record;
1371:
1372: /* mark this record as class template - for class type checking */
1373: TREE_STATIC_TEMPLATE (_PRIVATE_record) = 1;
1374: }
1375: instance_type = groktypename (
1376: build_tree_list (build_tree_list (NULLT, _PRIVATE_record),
1377: build1 (INDIRECT_REF, NULLT, NULLT)));
1378: return ivar_context;
1379: }
1380:
1381: /*
1382: * struct objc_category {
1383: * char *category_name;
1384: * char *class_name;
1385: * struct objc_method_list *instance_methods;
1386: * struct objc_method_list *class_methods;
1387: * };
1388: */
1389: static void
1390: build_category_template ()
1391: {
1392: tree decl_specs, field_decl, field_decl_chain;
1393:
1394: objc_category_template = start_struct (RECORD_TYPE,
1395: get_identifier (_TAG_CATEGORY));
1396: /* char *category_name; */
1397:
1398: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_CHAR]);
1399: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("category_name"));
1400: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1401: field_decl_chain = field_decl;
1402:
1403: /* char *class_name; */
1404:
1405: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_CHAR]);
1406: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("class_name"));
1407: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1408: chainon (field_decl_chain, field_decl);
1409:
1410: /* struct objc_method_list *instance_methods; */
1411:
1412: decl_specs = build_tree_list (NULLT, xref_tag (RECORD_TYPE,
1413: get_identifier (_TAG_METHOD_LIST)));
1414: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("instance_methods"));
1415: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1416: chainon (field_decl_chain, field_decl);
1417:
1418: /* struct objc_method_list *class_methods; */
1419:
1420: decl_specs = build_tree_list (NULLT, xref_tag (RECORD_TYPE,
1421: get_identifier (_TAG_METHOD_LIST)));
1422: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("class_methods"));
1423: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1424: chainon (field_decl_chain, field_decl);
1425:
1426: finish_struct (objc_category_template, field_decl_chain);
1427: }
1428:
1429: /*
1430: * struct objc_class {
1431: * struct objc_class *isa;
1432: * struct objc_class *super_class;
1433: * char *name;
1434: * long version;
1435: * long info;
1436: * long instance_size;
1437: * struct objc_ivar_list *ivars;
1438: * struct objc_method_list *methods;
1439: * struct objc_cache *cache;
1440: * };
1441: */
1442: static void
1443: build_class_template ()
1444: {
1445: tree decl_specs, field_decl, field_decl_chain;
1446:
1447: objc_class_template = start_struct (RECORD_TYPE, get_identifier (_TAG_CLASS));
1448:
1449: /* struct objc_class *isa; */
1450:
1451: decl_specs = build_tree_list (NULLT, objc_class_template);
1452: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("isa"));
1453: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1454: field_decl_chain = field_decl;
1455:
1456: /* struct objc_class *super_class; */
1457:
1458: decl_specs = build_tree_list (NULLT, objc_class_template);
1459: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("super_class"));
1460: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1461: chainon (field_decl_chain, field_decl);
1462:
1463: /* char *name; */
1464:
1465: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_CHAR]);
1466: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("name"));
1467: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1468: chainon (field_decl_chain, field_decl);
1469:
1470: /* long version; */
1471:
1472: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_LONG]);
1473: field_decl = get_identifier ("version");
1474: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1475: chainon (field_decl_chain, field_decl);
1476:
1477: /* long info; */
1478:
1479: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_LONG]);
1480: field_decl = get_identifier ("info");
1481: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1482: chainon (field_decl_chain, field_decl);
1483:
1484: /* long instance_size; */
1485:
1486: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_LONG]);
1487: field_decl = get_identifier ("instance_size");
1488: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1489: chainon (field_decl_chain, field_decl);
1490:
1491: /* struct objc_ivar_list *ivars; */
1492:
1493: decl_specs = build_tree_list (NULLT, xref_tag (RECORD_TYPE,
1494: get_identifier (_TAG_IVAR_LIST)));
1495: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("ivars"));
1496: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1497: chainon (field_decl_chain, field_decl);
1498:
1499: /* struct objc_method_list *methods; */
1500:
1501: decl_specs = build_tree_list (NULLT, xref_tag (RECORD_TYPE,
1502: get_identifier (_TAG_METHOD_LIST)));
1503: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("methods"));
1504: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1505: chainon (field_decl_chain, field_decl);
1506:
1507: /* struct objc_cache *cache; */
1508:
1509: decl_specs = build_tree_list (NULLT, xref_tag (RECORD_TYPE,
1510: get_identifier ("objc_cache")));
1511: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("cache"));
1512: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1513: chainon (field_decl_chain, field_decl);
1514:
1515: finish_struct (objc_class_template, field_decl_chain);
1516: }
1517:
1518: /*
1519: * generate appropriate forward declarations for an implementation
1520: */
1521: static void
1522: synth_forward_declarations ()
1523: {
1524: tree sc_spec, decl_specs, factory_id, anId;
1525:
1526: /* extern struct objc_class _OBJC_CLASS_<my_name>; */
1527:
1528: anId = synth_id_with_class_suffix ("_OBJC_CLASS");
1529:
1530: sc_spec = build_tree_list (NULLT, ridpointers[(int) RID_EXTERN]);
1531: decl_specs = tree_cons (NULLT, objc_class_template, sc_spec);
1532: _OBJC_CLASS_decl = define_decl (anId, decl_specs);
1533:
1534: /* extern struct objc_class _OBJC_METACLASS_<my_name>; */
1535:
1536: anId = synth_id_with_class_suffix ("_OBJC_METACLASS");
1537:
1538: _OBJC_METACLASS_decl = define_decl (anId, decl_specs);
1539:
1540: /* pre-build the following entities - for speed/convenience. */
1541:
1542: anId = get_identifier ("super_class");
1543: _clsSuper_ref = build_component_ref (_OBJC_CLASS_decl, anId);
1544: __clsSuper_ref = build_component_ref (_OBJC_METACLASS_decl, anId);
1545: }
1546:
1547: static void
1548: error_with_ivar (message, decl, rawdecl)
1549: char *message;
1550: tree decl;
1551: tree rawdecl;
1552: {
1553: count_error (0);
1554: fprintf (stderr, "%s:%d: ",
1555: DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
1556: bzero (errbuf, BUFSIZE);
1557: fprintf (stderr, "%s `%s'\n", message, gen_declaration (rawdecl, errbuf));
1558: }
1559:
1560: #define USERTYPE(t) (TREE_CODE (t) == RECORD_TYPE || \
1561: TREE_CODE (t) == UNION_TYPE || \
1562: TREE_CODE (t) == ENUMERAL_TYPE)
1563:
1564: static void
1565: check_ivars (inter, imp)
1566: tree inter;
1567: tree imp;
1568: {
1569: tree intdecls = CLASS_IVARS (inter);
1570: tree impdecls = CLASS_IVARS (imp);
1571: tree rawintdecls = CLASS_RAW_IVARS (inter);
1572: tree rawimpdecls = CLASS_RAW_IVARS (imp);
1573:
1574: while (1)
1575: {
1576: tree t1, t2;
1577:
1578: if (intdecls == 0 && impdecls == 0)
1579: break;
1580: if (intdecls == 0 || impdecls == 0)
1581: {
1582: error ("inconsistent instance variable specification");
1583: break;
1584: }
1585: t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
1586:
1587: if (!comptypes (t1, t2))
1588: {
1589: if (DECL_NAME (intdecls) == DECL_NAME (impdecls))
1590: {
1591: error_with_ivar ("conflicting instance variable type",
1592: impdecls, rawimpdecls);
1593: error_with_ivar ("previous declaration of",
1594: intdecls, rawintdecls);
1595: }
1596: else /* both the type and the name don't match */
1597: {
1598: error ("inconsistent instance variable specification");
1599: break;
1600: }
1601: }
1602: else if (DECL_NAME (intdecls) != DECL_NAME (impdecls))
1603: {
1604: error_with_ivar ("conflicting instance variable name",
1605: impdecls, rawimpdecls);
1606: error_with_ivar ("previous declaration of",
1607: intdecls, rawintdecls);
1608: }
1609: intdecls = TREE_CHAIN (intdecls);
1610: impdecls = TREE_CHAIN (impdecls);
1611: rawintdecls = TREE_CHAIN (rawintdecls);
1612: rawimpdecls = TREE_CHAIN (rawimpdecls);
1613: }
1614: }
1615:
1616: /*
1617: * struct objc_super {
1618: * id self;
1619: * struct objc_class *class;
1620: * };
1621: */
1622: static tree
1623: build_super_template ()
1624: {
1625: tree record, decl_specs, field_decl, field_decl_chain;
1626:
1627: record = start_struct (RECORD_TYPE, get_identifier (_TAG_SUPER));
1628:
1629: /* struct objc_object *self; */
1630:
1631: decl_specs = build_tree_list (NULLT, objc_object_reference);
1632: field_decl = get_identifier ("self");
1633: field_decl = build1 (INDIRECT_REF, NULLT, field_decl);
1634: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1635: field_decl_chain = field_decl;
1636:
1637: /* struct objc_class *class; */
1638:
1639: decl_specs = get_identifier (_TAG_CLASS);
1640: decl_specs = build_tree_list (NULLT, xref_tag (RECORD_TYPE, decl_specs));
1641: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("class"));
1642:
1643: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1644: chainon (field_decl_chain, field_decl);
1645:
1646: finish_struct (record, field_decl_chain);
1647:
1648: /* `struct objc_super *' */
1649: super_type = groktypename (build_tree_list (build_tree_list (NULLT, record),
1650: build1 (INDIRECT_REF, NULLT, NULLT)));
1651: return record;
1652: }
1653:
1654: /*
1655: * struct objc_ivar {
1656: * char *ivar_name;
1657: * char *ivar_type;
1658: * int ivar_offset;
1659: * };
1660: */
1661: static tree
1662: build_ivar_template ()
1663: {
1664: tree objc_ivar_id, objc_ivar_record;
1665: tree decl_specs, field_decl, field_decl_chain;
1666:
1667: objc_ivar_id = get_identifier (_TAG_IVAR);
1668: objc_ivar_record = start_struct (RECORD_TYPE, objc_ivar_id);
1669:
1670: /* char *ivar_name; */
1671:
1672: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_CHAR]);
1673: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("ivar_name"));
1674:
1675: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1676: field_decl_chain = field_decl;
1677:
1678: /* char *ivar_type; */
1679:
1680: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_CHAR]);
1681: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("ivar_type"));
1682:
1683: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1684: chainon (field_decl_chain, field_decl);
1685:
1686: /* int ivar_offset; */
1687:
1688: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_INT]);
1689: field_decl = get_identifier ("ivar_offset");
1690:
1691: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1692: chainon (field_decl_chain, field_decl);
1693:
1694: finish_struct (objc_ivar_record, field_decl_chain);
1695:
1696: return objc_ivar_record;
1697: }
1698:
1699: /*
1700: * struct {
1701: * int ivar_count;
1702: * struct objc_ivar ivar_list[ivar_count];
1703: * };
1704: */
1705: static tree
1706: build_ivar_list_template (list_type, size)
1707: tree list_type;
1708: int size;
1709: {
1710: tree objc_ivar_list_id, objc_ivar_list_record;
1711: tree decl_specs, field_decl, field_decl_chain;
1712:
1713: objc_ivar_list_record = start_struct (RECORD_TYPE, NULLT);
1714:
1715: /* int ivar_count; */
1716:
1717: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_INT]);
1718: field_decl = get_identifier ("ivar_count");
1719:
1720: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1721: field_decl_chain = field_decl;
1722:
1723: /* struct objc_ivar ivar_list[]; */
1724:
1725: decl_specs = build_tree_list (NULLT, list_type);
1726: field_decl = build_nt (ARRAY_REF, get_identifier ("ivar_list"),
1727: build_int_2 (size, 0));
1728:
1729: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1730: chainon (field_decl_chain, field_decl);
1731:
1732: finish_struct (objc_ivar_list_record, field_decl_chain);
1733:
1734: return objc_ivar_list_record;
1735: }
1736:
1737: /*
1738: * struct {
1739: * int method_next;
1740: * int method_count;
1741: * struct objc_method method_list[method_count];
1742: * };
1743: */
1744: static tree
1745: build_method_list_template (list_type, size)
1746: tree list_type;
1747: int size;
1748: {
1749: tree objc_ivar_list_id, objc_ivar_list_record;
1750: tree decl_specs, field_decl, field_decl_chain;
1751:
1752: objc_ivar_list_record = start_struct (RECORD_TYPE, NULLT);
1753:
1754: /* int method_next; */
1755:
1756: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_INT]);
1757: field_decl = get_identifier ("method_next");
1758:
1759: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1760: field_decl_chain = field_decl;
1761:
1762: /* int method_count; */
1763:
1764: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_INT]);
1765: field_decl = get_identifier ("method_count");
1766:
1767: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1768: chainon (field_decl_chain, field_decl);
1769:
1770: /* struct objc_method method_list[]; */
1771:
1772: decl_specs = build_tree_list (NULLT, list_type);
1773: field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
1774: build_int_2 (size, 0));
1775:
1776: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1777: chainon (field_decl_chain, field_decl);
1778:
1779: finish_struct (objc_ivar_list_record, field_decl_chain);
1780:
1781: return objc_ivar_list_record;
1782: }
1783:
1784: static tree
1785: build_ivar_list_initializer (field_decl, size)
1786: tree field_decl;
1787: int *size;
1788: {
1789: tree initlist = NULLT;
1790:
1791: do
1792: {
1793: int offset;
1794:
1795: /* set name */
1796: if (DECL_NAME (field_decl))
1797: {
1798: offset = add_objc_string (DECL_NAME (field_decl));
1799: initlist = tree_cons (NULLT, build_msg_pool_reference (offset), initlist);
1800: }
1801: else
1802: {
1803: /* unnamed bit-field ivar (yuck). */
1804: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
1805: }
1806:
1807: /* set type */
1808: bzero (utlbuf, BUFSIZE);
1809: encode_field_decl (field_decl, utlbuf, OBJC_ENCODE_DONT_INLINE_DEFS);
1810:
1811: offset = add_objc_string (get_identifier (utlbuf));
1812: initlist = tree_cons (NULLT, build_msg_pool_reference (offset), initlist);
1813:
1814: /* set offset */
1815: initlist = tree_cons (NULLT,
1816: build_int_2 (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field_decl)) / BITS_PER_UNIT, 0),
1817:
1818: initlist);
1819: (*size)++;
1820: field_decl = TREE_CHAIN (field_decl);
1821: }
1822: while (field_decl);
1823:
1824: return build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
1825: }
1826:
1827: static tree
1828: generate_ivars_list (type, name, size, list)
1829: tree type;
1830: char *name;
1831: int size;
1832: tree list;
1833: {
1834: tree sc_spec, decl_specs, decl, initlist;
1835:
1836: sc_spec = tree_cons (NULLT, ridpointers[(int) RID_STATIC], NULLT);
1837: decl_specs = tree_cons (NULLT, type, sc_spec);
1838:
1839: decl = start_decl (synth_id_with_class_suffix (name), decl_specs, 1);
1840:
1841: initlist = build_tree_list (NULLT, build_int_2 (size, 0));
1842: initlist = tree_cons (NULLT, list, initlist);
1843:
1844: finish_decl (decl, build_nt (CONSTRUCTOR, NULLT, nreverse (initlist)), NULLT);
1845:
1846: return decl;
1847: }
1848:
1849: static void
1850: generate_ivar_lists ()
1851: {
1852: tree initlist, ivar_list_template, chain;
1853: tree cast, variable_length_type;
1854: int size;
1855:
1856: if (!objc_ivar_template)
1857: objc_ivar_template = build_ivar_template ();
1858:
1859: cast = build_tree_list (build_tree_list (NULLT, xref_tag (RECORD_TYPE,
1860: get_identifier (_TAG_IVAR_LIST))), NULLT);
1861: variable_length_type = groktypename (cast);
1862:
1863: /* only generate class variables for the root of the inheritance
1864: hierarchy since these will be the same for every class */
1865:
1866: if (CLASS_SUPER_NAME (implementation_template) == NULLT
1867: && (chain = TYPE_FIELDS (objc_class_template)))
1868: {
1869: size = 0;
1870: initlist = build_ivar_list_initializer (chain, &size);
1871:
1872: ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
1873:
1874: _OBJC_CLASS_VARIABLES_decl =
1875: generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES",
1876: size, initlist);
1877: /* cast! */
1878: TREE_TYPE (_OBJC_CLASS_VARIABLES_decl) = variable_length_type;
1879: }
1880: else
1881: _OBJC_CLASS_VARIABLES_decl = 0;
1882:
1883: chain = CLASS_IVARS (implementation_template);
1884: if (chain)
1885: {
1886: size = 0;
1887: initlist = build_ivar_list_initializer (chain, &size);
1888:
1889: ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
1890:
1891: _OBJC_INSTANCE_VARIABLES_decl =
1892: generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES",
1893: size, initlist);
1894: /* cast! */
1895: TREE_TYPE (_OBJC_INSTANCE_VARIABLES_decl) = variable_length_type;
1896: }
1897: else
1898: _OBJC_INSTANCE_VARIABLES_decl = 0;
1899: }
1900:
1901: static tree
1902: build_dispatch_table_initializer (entries, size)
1903: tree entries;
1904: int *size;
1905: {
1906: tree initlist = NULLT;
1907:
1908: do
1909: {
1910: int offset = add_objc_string (METHOD_SEL_NAME (entries));
1911:
1912: initlist = tree_cons (NULLT, init_selector (offset), initlist);
1913:
1914: offset = add_objc_string (METHOD_ENCODING (entries));
1915: initlist = tree_cons (NULLT, build_msg_pool_reference (offset), initlist);
1916:
1917: initlist = tree_cons (NULLT, METHOD_DEFINITION (entries), initlist);
1918:
1919: (*size)++;
1920: entries = TREE_CHAIN (entries);
1921: }
1922: while (entries);
1923:
1924: return build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
1925: }
1926:
1927: /*
1928: * To accomplish method prototyping without generating all kinds of
1929: * inane warnings, the definition of the dispatch table entries were
1930: * changed from:
1931: *
1932: * struct objc_method { SEL _cmd; id (*_imp)(); };
1933: * to:
1934: * struct objc_method { SEL _cmd; void *_imp; };
1935: */
1936: static tree
1937: build_method_template ()
1938: {
1939: tree _SLT_record;
1940: tree decl_specs, field_decl, field_decl_chain, parms;
1941:
1942: _SLT_record = start_struct (RECORD_TYPE, get_identifier (_TAG_METHOD));
1943:
1944: #ifdef OBJC_INT_SELECTORS
1945: /* unsigned int _cmd; */
1946: decl_specs = tree_cons (NULLT, ridpointers[(int) RID_UNSIGNED], NULLT);
1947: decl_specs = tree_cons (NULLT, ridpointers[(int) RID_INT], decl_specs);
1948: field_decl = get_identifier ("_cmd");
1949: #else /* not OBJC_INT_SELECTORS */
1950: /* struct objc_selector *_cmd; */
1951: decl_specs = tree_cons (NULLT,
1952: xref_tag (RECORD_TYPE,
1953: get_identifier (TAG_SELECTOR)),
1954: NULLT);
1955: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("_cmd"));
1956: #endif /* not OBJC_INT_SELECTORS */
1957:
1958: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1959: field_decl_chain = field_decl;
1960:
1961: decl_specs = tree_cons (NULLT, ridpointers[(int) RID_CHAR], NULLT);
1962: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("method_types"));
1963: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1964: chainon (field_decl_chain, field_decl);
1965:
1966: /* void *_imp; */
1967:
1968: decl_specs = tree_cons (NULLT, ridpointers[(int) RID_VOID], NULLT);
1969: field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("_imp"));
1970: field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
1971: chainon (field_decl_chain, field_decl);
1972:
1973: finish_struct (_SLT_record, field_decl_chain);
1974:
1975: return _SLT_record;
1976: }
1977:
1978:
1979: static tree
1980: generate_dispatch_table (type, name, size, list)
1981: tree type;
1982: char *name;
1983: int size;
1984: tree list;
1985: {
1986: tree sc_spec, decl_specs, decl, initlist;
1987:
1988: sc_spec = tree_cons (NULLT, ridpointers[(int) RID_STATIC], NULLT);
1989: decl_specs = tree_cons (NULLT, type, sc_spec);
1990:
1991: decl = start_decl (synth_id_with_class_suffix (name), decl_specs, 1);
1992:
1993: initlist = build_tree_list (NULLT, build_int_2 (0, 0));
1994: initlist = tree_cons (NULLT, build_int_2 (size, 0), initlist);
1995: initlist = tree_cons (NULLT, list, initlist);
1996:
1997: finish_decl (decl, build_nt (CONSTRUCTOR, NULLT, nreverse (initlist)), NULLT);
1998:
1999: return decl;
2000: }
2001:
2002: static void
2003: generate_dispatch_tables ()
2004: {
2005: tree initlist, chain, method_list_template;
2006: tree cast, variable_length_type;
2007: int size;
2008:
2009: if (!objc_method_template)
2010: objc_method_template = build_method_template ();
2011:
2012: cast = build_tree_list (build_tree_list (NULLT, xref_tag (RECORD_TYPE,
2013: get_identifier (_TAG_METHOD_LIST))), NULLT);
2014: variable_length_type = groktypename (cast);
2015:
2016: chain = CLASS_CLS_METHODS (implementation_context);
2017: if (chain)
2018: {
2019: size = 0;
2020: initlist = build_dispatch_table_initializer (chain, &size);
2021:
2022: method_list_template = build_method_list_template (objc_method_template,
2023: size);
2024: if (TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE)
2025: _OBJC_CLASS_METHODS_decl =
2026: generate_dispatch_table (method_list_template,
2027: "_OBJC_CLASS_METHODS",
2028: size, initlist);
2029: else
2030: /* we have a category */
2031: _OBJC_CLASS_METHODS_decl =
2032: generate_dispatch_table (method_list_template,
2033: "_OBJC_CATEGORY_CLASS_METHODS",
2034: size, initlist);
2035: /* cast! */
2036: TREE_TYPE (_OBJC_CLASS_METHODS_decl) = variable_length_type;
2037: }
2038: else
2039: _OBJC_CLASS_METHODS_decl = 0;
2040:
2041: chain = CLASS_NST_METHODS (implementation_context);
2042: if (chain)
2043: {
2044: size = 0;
2045: initlist = build_dispatch_table_initializer (chain, &size);
2046:
2047: method_list_template = build_method_list_template (objc_method_template,
2048: size);
2049: if (TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE)
2050: _OBJC_INSTANCE_METHODS_decl =
2051: generate_dispatch_table (method_list_template,
2052: "_OBJC_INSTANCE_METHODS",
2053: size, initlist);
2054: else
2055: /* we have a category */
2056: _OBJC_INSTANCE_METHODS_decl =
2057: generate_dispatch_table (method_list_template,
2058: "_OBJC_CATEGORY_INSTANCE_METHODS",
2059: size, initlist);
2060: /* cast! */
2061: TREE_TYPE (_OBJC_INSTANCE_METHODS_decl) = variable_length_type;
2062: }
2063: else
2064: _OBJC_INSTANCE_METHODS_decl = 0;
2065: }
2066:
2067: static tree
2068: build_category_initializer (cat_name, class_name,
2069: instance_methods, class_methods)
2070: tree cat_name;
2071: tree class_name;
2072: tree instance_methods;
2073: tree class_methods;
2074: {
2075: tree initlist = NULLT, expr;
2076:
2077: initlist = tree_cons (NULLT, cat_name, initlist);
2078: initlist = tree_cons (NULLT, class_name, initlist);
2079:
2080: if (!instance_methods)
2081: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
2082: else
2083: {
2084: expr = build_unary_op (ADDR_EXPR, instance_methods, 0);
2085: initlist = tree_cons (NULLT, expr, initlist);
2086: }
2087: if (!class_methods)
2088: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
2089: else
2090: {
2091: expr = build_unary_op (ADDR_EXPR, class_methods, 0);
2092: initlist = tree_cons (NULLT, expr, initlist);
2093: }
2094: return build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
2095: }
2096:
2097: /*
2098: * struct objc_class {
2099: * struct objc_class *isa;
2100: * struct objc_class *super_class;
2101: * char *name;
2102: * long version;
2103: * long info;
2104: * long instance_size;
2105: * struct objc_ivar_list *ivars;
2106: * struct objc_method_list *methods;
2107: * struct objc_cache *cache;
2108: * };
2109: */
2110: static tree
2111: build_shared_structure_initializer (isa, super, name, size, status,
2112: dispatch_table, ivar_list)
2113: tree isa;
2114: tree super;
2115: tree name;
2116: tree size;
2117: int status;
2118: tree dispatch_table;
2119: tree ivar_list;
2120: {
2121: tree initlist = NULLT, expr;
2122:
2123: /* isa = */
2124: initlist = tree_cons (NULLT, isa, initlist);
2125:
2126: /* super_class = */
2127: initlist = tree_cons (NULLT, super, initlist);
2128:
2129: /* name = */
2130: initlist = tree_cons (NULLT, name, initlist);
2131:
2132: /* version = */
2133: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
2134:
2135: /* info = */
2136: initlist = tree_cons (NULLT, build_int_2 (status), initlist);
2137:
2138: /* instance_size = */
2139: initlist = tree_cons (NULLT, size, initlist);
2140:
2141: /* objc_ivar_list = */
2142: if (!ivar_list)
2143: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
2144: else
2145: {
2146: expr = build_unary_op (ADDR_EXPR, ivar_list, 0);
2147: initlist = tree_cons (NULLT, expr, initlist);
2148: }
2149:
2150: /* objc_method_list = */
2151: if (!dispatch_table)
2152: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
2153: else
2154: {
2155: expr = build_unary_op (ADDR_EXPR, dispatch_table, 0);
2156: initlist = tree_cons (NULLT, expr, initlist);
2157: }
2158:
2159: /* method_cache = */
2160: initlist = tree_cons (NULLT, build_int_2 (0, 0), initlist);
2161:
2162: return build_nt (CONSTRUCTOR, NULLT, nreverse (initlist));
2163: }
2164:
2165: /*
2166: * static struct objc_category _OBJC_CATEGORY_<name> = { ... };
2167: */
2168: static void
2169: generate_category (cat)
2170: tree cat;
2171: {
2172: tree sc_spec, decl_specs, decl;
2173: tree initlist, cat_name_expr, class_name_expr;
2174: int offset;
2175:
2176: sc_spec = tree_cons (NULLT, ridpointers[(int) RID_STATIC], NULLT);
2177: decl_specs = tree_cons (NULLT, objc_category_template, sc_spec);
2178:
2179: decl = start_decl (synth_id_with_class_suffix ("_OBJC_CATEGORY"),
2180: decl_specs, 1);
2181:
2182: offset = add_objc_string (CLASS_SUPER_NAME (cat));
2183: cat_name_expr = build_msg_pool_reference (offset);
2184:
2185: offset = add_objc_string (CLASS_NAME (cat));
2186: class_name_expr = build_msg_pool_reference (offset);
2187:
2188: initlist = build_category_initializer (
2189: cat_name_expr, class_name_expr,
2190: _OBJC_INSTANCE_METHODS_decl, _OBJC_CLASS_METHODS_decl);
2191:
2192: finish_decl (decl, initlist, NULLT);
2193: }
2194:
2195: /*
2196: * static struct objc_class _OBJC_METACLASS_Foo={ ... };
2197: * static struct objc_class _OBJC_CLASS_Foo={ ... };
2198: */
2199: static void
2200: generate_shared_structures ()
2201: {
2202: tree sc_spec, decl_specs, expr_decl, decl;
2203: tree name_expr, super_expr, root_expr;
2204: tree my_root_id = NULLT, my_super_id = NULLT;
2205: tree cast_type, initlist;
2206: int offset;
2207:
2208: my_super_id = CLASS_SUPER_NAME (implementation_template);
2209: if (my_super_id)
2210: {
2211: add_class_reference (my_super_id);
2212:
2213: /* compute "my_root_id" - this is required for code generation.
2214: * the "isa" for all meta class structures points to the root of
2215: * the inheritance hierarchy (e.g. "__Object")...
2216: */
2217: my_root_id = my_super_id;
2218: do
2219: {
2220: tree my_root_int = lookup_interface (my_root_id);
2221:
2222: if (my_root_int && CLASS_SUPER_NAME (my_root_int))
2223: my_root_id = CLASS_SUPER_NAME (my_root_int);
2224: else
2225: break;
2226: }
2227: while (1);
2228: }
2229: else /* no super class */
2230: {
2231: my_root_id = CLASS_NAME (implementation_template);
2232: }
2233:
2234: cast_type = groktypename (build_tree_list (build_tree_list (NULLT,
2235: objc_class_template), build1 (INDIRECT_REF, NULLT, NULLT)));
2236:
2237: offset = add_objc_string (CLASS_NAME (implementation_template));
2238: name_expr = build_msg_pool_reference (offset);
2239:
2240: /* install class `isa' and `super' pointers at runtime */
2241: if (my_super_id)
2242: {
2243: offset = add_objc_string (my_super_id);
2244: super_expr = build_msg_pool_reference (offset);
2245: TREE_TYPE (super_expr) = cast_type; /* cast! */
2246: }
2247: else
2248: super_expr = build_int_2 (0, 0);
2249:
2250: offset = add_objc_string (my_root_id);
2251: root_expr = build_msg_pool_reference (offset);
2252: TREE_TYPE (root_expr) = cast_type; /* cast! */
2253:
2254: /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */
2255:
2256: sc_spec = build_tree_list (NULLT, ridpointers[(int) RID_STATIC]);
2257: decl_specs = tree_cons (NULLT, objc_class_template, sc_spec);
2258:
2259: decl = start_decl (DECL_NAME (_OBJC_METACLASS_decl), decl_specs, 1);
2260:
2261: initlist = build_shared_structure_initializer (
2262: root_expr, super_expr, name_expr,
2263: build_int_2 (TREE_INT_CST_LOW (TYPE_SIZE (objc_class_template)) / BITS_PER_UNIT, 0),
2264: 2 /*CLS_META*/,
2265: _OBJC_CLASS_METHODS_decl, _OBJC_CLASS_VARIABLES_decl);
2266:
2267: finish_decl (decl, initlist, NULLT);
2268:
2269: /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */
2270:
2271: decl = start_decl (DECL_NAME (_OBJC_CLASS_decl), decl_specs, 1);
2272:
2273: initlist = build_shared_structure_initializer (
2274: build_unary_op (ADDR_EXPR, _OBJC_METACLASS_decl, 0),
2275: super_expr, name_expr,
2276: build_int_2 (TREE_INT_CST_LOW (TYPE_SIZE (CLASS_STATIC_TEMPLATE (implementation_template))) / BITS_PER_UNIT, 0),
2277: 1 /*CLS_FACTORY*/,
2278: _OBJC_INSTANCE_METHODS_decl, _OBJC_INSTANCE_VARIABLES_decl);
2279:
2280: finish_decl (decl, initlist, NULLT);
2281: }
2282:
2283: static tree
2284: synth_id_with_class_suffix (preamble)
2285: char *preamble;
2286: {
2287: if (TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE)
2288: sprintf (utlbuf, "%s_%s", preamble,
2289: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)));
2290: else
2291: /* we have a category */
2292: sprintf (utlbuf, "%s_%s_%s", preamble,
2293: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)),
2294: IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)));
2295: return get_identifier (utlbuf);
2296: }
2297:
2298: /*
2299: * usage:
2300: * keyworddecl:
2301: * selector ':' '(' typename ')' identifier
2302: *
2303: * purpose:
2304: * transform an Objective-C keyword argument into
2305: * the C equivalent parameter declarator.
2306: *
2307: * in: key_name, an "identifier_node" (optional).
2308: * arg_type, a "tree_list" (optional).
2309: * arg_name, an "identifier_node".
2310: *
2311: * note: it would be really nice to strongly type the preceding
2312: * arguments in the function prototype; however, then i
2313: * could not use the "accessor" macros defined in "tree.h".
2314: *
2315: * out: an instance of "keyword_decl".
2316: *
2317: */
2318:
2319: tree
2320: build_keyword_decl (key_name, arg_type, arg_name)
2321: tree key_name;
2322: tree arg_type;
2323: tree arg_name;
2324: {
2325: tree keyword_decl;
2326:
2327: /* if no type is specified, default to "id" */
2328: if (arg_type == NULLT)
2329: arg_type = build_tree_list (build_tree_list (NULLT, objc_object_reference),
2330: build1 (INDIRECT_REF, NULLT, NULLT));
2331:
2332: keyword_decl = make_node (KEYWORD_DECL);
2333:
2334: TREE_TYPE (keyword_decl) = arg_type;
2335: KEYWORD_ARG_NAME (keyword_decl) = arg_name;
2336: KEYWORD_KEY_NAME (keyword_decl) = key_name;
2337:
2338: return keyword_decl;
2339: }
2340:
2341: /*
2342: * given a chain of keyword_decl's, synthesize the full keyword selector.
2343: */
2344: static tree
2345: build_keyword_selector (selector)
2346: tree selector;
2347: {
2348: int len = 0;
2349: tree key_chain, key_name;
2350: char *buf;
2351:
2352: for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
2353: {
2354: if (TREE_CODE (selector) == KEYWORD_DECL)
2355: key_name = KEYWORD_KEY_NAME (key_chain);
2356: else if (TREE_CODE (selector) == TREE_LIST)
2357: key_name = TREE_PURPOSE (key_chain);
2358:
2359: if (key_name)
2360: len += IDENTIFIER_LENGTH (key_name) + 1;
2361: else /* just a ':' arg */
2362: len++;
2363: }
2364: buf = (char *)alloca (len + 1);
2365: bzero (buf, len + 1);
2366:
2367: for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
2368: {
2369: if (TREE_CODE (selector) == KEYWORD_DECL)
2370: key_name = KEYWORD_KEY_NAME (key_chain);
2371: else if (TREE_CODE (selector) == TREE_LIST)
2372: key_name = TREE_PURPOSE (key_chain);
2373:
2374: if (key_name)
2375: strcat (buf, IDENTIFIER_POINTER (key_name));
2376: strcat (buf, ":");
2377: }
2378: return get_identifier (buf);
2379: }
2380:
2381: /* used for declarations and definitions */
2382:
2383: tree
2384: build_method_decl (code, ret_type, selector, add_args)
2385: enum tree_code code;
2386: tree ret_type;
2387: tree selector;
2388: tree add_args;
2389: {
2390: tree method_decl;
2391:
2392: /* if no type is specified, default to "id" */
2393: if (ret_type == NULLT)
2394: ret_type = build_tree_list (build_tree_list (NULLT, objc_object_reference),
2395: build1 (INDIRECT_REF, NULLT, NULLT));
2396:
2397: method_decl = make_node (code);
2398: TREE_TYPE (method_decl) = ret_type;
2399:
2400: /*
2401: * if we have a keyword selector, create an identifier_node that
2402: * represents the full selector name (`:' included)...
2403: */
2404: if (TREE_CODE (selector) == KEYWORD_DECL)
2405: {
2406: METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector);
2407: METHOD_SEL_ARGS (method_decl) = selector;
2408: METHOD_ADD_ARGS (method_decl) = add_args;
2409: }
2410: else
2411: {
2412: METHOD_SEL_NAME (method_decl) = selector;
2413: METHOD_SEL_ARGS (method_decl) = NULLT;
2414: METHOD_ADD_ARGS (method_decl) = NULLT;
2415: }
2416:
2417: return method_decl;
2418: }
2419:
2420: #define METHOD_DEF 0
2421: #define METHOD_REF 1
1.1.1.2 ! root 2422: /* Used by `build_message_expr' and `comp_method_types'.
! 2423: Return an argument list for method METH.
! 2424: CONTEXT is either METHOD_DEF or METHOD_REF,
! 2425: saying whether we are trying to define a method or call one.
! 2426: SUPERFLAG says this is for a send to super;
! 2427: this makes a difference for the NeXT calling sequence
! 2428: in which the lookup and the method call are done together. */
! 2429:
1.1 root 2430: static tree
2431: get_arg_type_list (meth, context, superflag)
2432: tree meth;
2433: int context;
2434: int superflag;
2435: {
2436: tree arglist, akey;
2437:
1.1.1.2 ! root 2438: #ifdef NEXT_OBJC_RUNTIME
1.1 root 2439: /* receiver type */
2440: if (superflag)
1.1.1.2 ! root 2441: {
! 2442: arglist = build_tree_list (NULLT, super_type);
! 2443: }
1.1 root 2444: else
1.1.1.2 ! root 2445: #endif
1.1 root 2446: {
2447: if (context == METHOD_DEF)
2448: arglist = build_tree_list (NULLT, TREE_TYPE (self_decl));
2449: else
2450: arglist = build_tree_list (NULLT, id_type);
2451: }
2452:
2453: /* selector type - will eventually change to `int' */
1.1.1.2 ! root 2454: chainon (arglist, build_tree_list (NULLT, selector_type));
1.1 root 2455:
2456: /* build a list of argument types */
2457: for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey))
2458: {
2459: tree arg_decl = groktypename_in_parm_context (TREE_TYPE (akey));
2460: chainon (arglist, build_tree_list (NULLT, TREE_TYPE (arg_decl)));
2461: }
2462:
2463: if (METHOD_ADD_ARGS (meth) == (tree)1)
2464: /*
2465: * we have a `, ...' immediately following the selector,
2466: * finalize the arglist...simulate get_parm_info (0)
2467: */
2468: ;
2469: else if (METHOD_ADD_ARGS (meth))
2470: {
2471: /* we have a variable length selector */
2472: tree add_arg_list = TREE_CHAIN (METHOD_ADD_ARGS (meth));
2473: chainon (arglist, add_arg_list);
2474: }
2475: else /* finalize the arglist...simulate get_parm_info (1) */
2476: chainon (arglist, build_tree_list (NULLT, void_type_node));
2477:
2478: return arglist;
2479: }
2480:
2481: static tree
2482: check_duplicates (hsh)
2483: hash hsh;
2484: {
2485: tree meth = NULLT;
2486:
2487: if (hsh)
2488: {
2489: meth = hsh->key;
2490:
2491: if (hsh->list)
2492: {
2493: /* we have two methods with the same name and different types */
2494: attr loop;
2495: char type;
2496:
2497: type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+';
2498:
2499: warning ("multiple declarations for method `%s'",
2500: IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
2501:
2502: warn_with_method ("using", type, meth);
2503: for (loop = hsh->list; loop; loop = loop->next)
2504: warn_with_method ("also found", type, loop->value);
2505: }
2506: }
2507: return meth;
2508: }
2509:
2510: static tree
2511: receiver_is_class_object (receiver)
2512: tree receiver;
2513: {
2514: /* the receiver is a function call that returns an id...
2515: * ...check if it is a call to objc_getClass, if so, give it
2516: * special treatment.
2517: */
1.1.1.2 ! root 2518: tree exp = TREE_OPERAND (receiver, 0);
1.1 root 2519:
1.1.1.2 ! root 2520: if (exp != 0 && (TREE_CODE (exp) == ADDR_EXPR))
1.1 root 2521: {
1.1.1.2 ! root 2522: exp = TREE_OPERAND (exp, 0);
! 2523: if (exp != 0
! 2524: && TREE_CODE (exp) == FUNCTION_DECL && exp == objc_getClass_decl)
1.1 root 2525: {
2526: /* we have a call to objc_getClass! */
1.1.1.2 ! root 2527: tree arg = TREE_OPERAND (receiver, 1);
! 2528:
! 2529: if (arg != 0
! 2530: && TREE_CODE (arg) == TREE_LIST
! 2531: && (arg = TREE_VALUE (arg))
! 2532: && TREE_CODE (arg) == NOP_EXPR
! 2533: && (arg = TREE_OPERAND (arg, 0))
! 2534: && TREE_CODE (arg) == ADDR_EXPR
! 2535: && (arg = TREE_OPERAND (arg, 0))
! 2536: && TREE_CODE (arg) == STRING_CST)
1.1 root 2537: /* finally, we have the class name */
2538: return get_identifier (TREE_STRING_POINTER (arg));
2539: }
2540: }
2541: return 0;
2542: }
2543:
2544: /* If we are currently building a message expr, this holds
2545: the identifier of the selector of the message. This is
2546: used when printing warnings about argument mismatches. */
2547:
2548: static tree building_objc_message_expr = 0;
2549:
2550: tree
2551: maybe_building_objc_message_expr ()
2552: {
2553: return building_objc_message_expr;
2554: }
2555:
2556: /* Construct an expression for sending a message.
2557: MESS has the object to send to in TREE_PURPOSE
2558: and the argument list (including selector) in TREE_VALUE. */
2559:
2560: tree
2561: build_message_expr (mess)
2562: tree mess;
2563: {
2564: tree receiver = TREE_PURPOSE (mess);
2565: tree selector, self_object;
2566: tree rtype, sel_name;
2567: tree args = TREE_VALUE (mess);
2568: tree method_params = NULLT;
2569: tree method_prototype = NULLT;
2570: int selTransTbl_index;
2571: tree retval;
2572: int statically_typed = 0, statically_allocated = 0;
2573: tree class_ident = 0;
2574:
2575: /* 1 if this is sending to the superclass. */
2576: int super;
2577:
2578: if (!doing_objc_thang)
2579: fatal ("Objective-C text in C source file");
2580:
2581: if (TREE_CODE (receiver) == ERROR_MARK)
2582: return error_mark_node;
2583:
2584: /* determine receiver type */
2585: rtype = TREE_TYPE (receiver);
2586: super = (TREE_TYPE (receiver) == super_type);
2587:
2588: if (! super)
2589: {
2590: if (TREE_STATIC_TEMPLATE (rtype))
2591: statically_allocated = 1;
2592: else if (TREE_CODE (rtype) == POINTER_TYPE
2593: && TREE_STATIC_TEMPLATE (TREE_TYPE (rtype)))
2594: statically_typed = 1;
2595: /* classfix -smn */
2596: else if (TREE_CODE (receiver) == CALL_EXPR && rtype == id_type
2597: && (class_ident = receiver_is_class_object (receiver)))
2598: ;
2599: else if (rtype != id_type && rtype != class_type)
2600: {
2601: bzero (errbuf, BUFSIZE);
2602: warning ("invalid receiver type `%s'", gen_declaration (rtype, errbuf));
2603: }
2604: if (statically_allocated)
2605: receiver = build_unary_op (ADDR_EXPR, receiver, 0);
2606:
2607: self_object = receiver;
2608: }
2609: else
2610: /* If sending to `super', use current self as the object. */
2611: self_object = self_decl;
2612:
2613: /* Obtain the full selector name. */
2614:
2615: if (TREE_CODE (args) == IDENTIFIER_NODE)
2616: /* a unary selector */
2617: sel_name = args;
2618: else if (TREE_CODE (args) == TREE_LIST)
2619: sel_name = build_keyword_selector (args);
2620:
2621: selTransTbl_index = add_selector_reference (sel_name);
2622:
2623: /* Build the parameters list for looking up the method.
2624: These are the object itself and the selector. */
2625:
2626: #ifndef OBJC_NONUNIQUE_SELECTORS
2627: selector = build_selector_reference (selTransTbl_index);
2628: #else
2629: selector = build_array_ref (_OBJC_SELECTOR_REFERENCES_decl,
2630: build_int_2 (selTransTbl_index, 0));
2631: #endif
2632:
2633: /* Build the parameter list to give to the method. */
2634:
2635: method_params = NULLT;
2636: if (TREE_CODE (args) == TREE_LIST)
2637: {
2638: tree chain = args, prev = NULLT;
2639:
2640: /* We have a keyword selector--check for comma expressions. */
2641: while (chain)
2642: {
2643: tree element = TREE_VALUE (chain);
2644:
2645: /* We have a comma expression, must collapse... */
2646: if (TREE_CODE (element) == TREE_LIST)
2647: {
2648: if (prev)
2649: TREE_CHAIN (prev) = element;
2650: else
2651: args = element;
2652: }
2653: prev = chain;
2654: chain = TREE_CHAIN (chain);
2655: }
2656: method_params = args;
2657: }
2658:
2659: /* Determine operation return type. */
2660:
2661: if (rtype == super_type)
2662: {
2663: tree iface;
2664:
2665: if (CLASS_SUPER_NAME (implementation_template))
2666: {
2667: iface = lookup_interface (CLASS_SUPER_NAME (implementation_template));
2668:
2669: if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL)
2670: method_prototype = lookup_instance_method_static (iface, sel_name);
2671: else
2672: method_prototype = lookup_class_method_static (iface, sel_name);
2673:
2674: if (iface && !method_prototype)
2675: warning ("`%s' does not respond to `%s'",
2676: IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template)),
2677: IDENTIFIER_POINTER (sel_name));
2678: }
2679: else
2680: {
2681: error ("no super class declared in interface for `%s'",
2682: IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
2683: return error_mark_node;
2684: }
2685:
2686: }
2687: else if (statically_allocated)
2688: {
2689: tree iface = lookup_interface (TYPE_NAME (rtype));
2690:
2691: if (iface && !(method_prototype = lookup_instance_method_static (iface, sel_name)))
2692: warning ("`%s' does not respond to `%s'",
2693: IDENTIFIER_POINTER (TYPE_NAME (rtype)),
2694: IDENTIFIER_POINTER (sel_name));
2695: }
2696: else if (statically_typed)
2697: {
2698: tree ctype = TREE_TYPE (rtype);
2699:
2700: /* `self' is now statically_typed...all methods should be visible
2701: * within the context of the implementation...
2702: */
2703: if (implementation_context
2704: && CLASS_NAME (implementation_context) == TYPE_NAME (ctype))
2705: {
2706: method_prototype = lookup_instance_method_static (implementation_template, sel_name);
2707:
2708: if (!method_prototype && implementation_template != implementation_context)
2709: /* the method is not published in the interface...check locally */
2710: method_prototype = lookup_method (CLASS_NST_METHODS (implementation_context),
2711: sel_name);
2712: }
2713: else
2714: {
2715: tree iface;
2716:
2717: if (iface = lookup_interface (TYPE_NAME (ctype)))
2718: method_prototype = lookup_instance_method_static (iface, sel_name);
2719: }
2720:
2721: if (!method_prototype)
2722: warning ("`%s' does not respond to `%s'",
2723: IDENTIFIER_POINTER (TYPE_NAME (ctype)),
2724: IDENTIFIER_POINTER (sel_name));
2725: }
2726: else if (class_ident)
2727: {
2728: if (implementation_context
2729: && CLASS_NAME (implementation_context) == class_ident)
2730: {
2731: method_prototype
2732: = lookup_class_method_static (implementation_template, sel_name);
2733:
2734: if (!method_prototype
2735: && implementation_template != implementation_context)
2736: /* the method is not published in the interface...check locally */
2737: method_prototype
2738: = lookup_method (CLASS_CLS_METHODS (implementation_context),
2739: sel_name);
2740: }
2741: else
2742: {
2743: tree iface;
2744:
2745: if (iface = lookup_interface (class_ident))
2746: method_prototype = lookup_class_method_static (iface, sel_name);
2747: }
2748:
2749: if (!method_prototype)
2750: {
2751: warning ("cannot find class (factory) method.");
2752: warning ("return type for `%s' defaults to id",
2753: IDENTIFIER_POINTER (sel_name));
2754: }
2755: }
2756: else
2757: {
2758: hash hsh;
2759:
2760: /* we think we have an instance...loophole: extern id Object; */
2761: hsh = hash_lookup (nst_method_hash_list, sel_name);
2762: if (!hsh)
2763: /* for various loopholes...like sending messages to self in a
2764: factory context... */
2765: hsh = hash_lookup (cls_method_hash_list, sel_name);
2766:
2767: method_prototype = check_duplicates (hsh);
2768: if (!method_prototype)
2769: {
2770: warning ("cannot find method.");
2771: warning ("return type for `%s' defaults to id",
2772: IDENTIFIER_POINTER (sel_name));
2773: }
2774: }
2775:
2776: /* Save the selector name for printing error messages. */
2777: building_objc_message_expr = sel_name;
2778:
2779: retval = build_objc_method_call (super, method_prototype,
2780: receiver, self_object,
2781: selector, method_params);
2782:
2783: building_objc_message_expr = 0;
2784:
2785: return retval;
2786: }
2787:
2788: /* Build a tree expression to send OBJECT the operation SELECTOR,
2789: looking up the method on object LOOKUP_OBJECT (often same as OBJECT),
2790: assuming the method has prototype METHOD_PROTOTYPE.
2791: (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.)
2792: Use METHOD_PARAMS as list of args to pass to the method.
2793: If SUPER_FLAG is nonzero, we look up the superclass's method. */
2794:
2795: static tree
2796: build_objc_method_call (super_flag, method_prototype, lookup_object, object,
2797: selector, method_params)
2798: int super_flag;
2799: tree method_prototype, lookup_object, object, selector, method_params;
2800: {
2801: tree sender = (super_flag ? _msgSuper_decl : _msg_decl);
2802:
2803: #ifdef NEXT_OBJC_RUNTIME
2804: if (!method_prototype)
2805: {
2806: method_params = tree_cons (NULLT, lookup_object,
2807: tree_cons (NULLT, selector, method_params));
2808: return build_function_call (sender, method_params);
2809: }
2810: else
2811: {
2812: /* This is a real kludge, but it is used only for the Next.
2813: Clobber the data type of SENDER temporarily to accept
2814: all the arguments for this operation, and to return
2815: whatever this operation returns. */
2816: tree arglist = NULLT;
2817: tree retval;
2818:
2819: /* Save the proper contents of SENDER's data type. */
2820: tree savarg = TYPE_ARG_TYPES (TREE_TYPE (sender));
2821: tree savret = TREE_TYPE (TREE_TYPE (sender));
2822:
2823: /* Install this method's argument types. */
2824: arglist = get_arg_type_list (method_prototype, METHOD_REF, super_flag);
2825: TYPE_ARG_TYPES (TREE_TYPE (sender)) = arglist;
2826:
2827: /* Install this method's return type. */
2828: TREE_TYPE (TREE_TYPE (sender))
2829: = groktypename (TREE_TYPE (method_prototype));
2830:
2831: /* Call SENDER with all the parameters.
2832: This will do type checking using the arg types for this method. */
2833: method_params = tree_cons (NULLT, lookup_object,
2834: tree_cons (NULLT, selector, method_params));
2835: retval = build_function_call (sender, method_params);
2836:
2837: /* Restore SENDER's return/argument types. */
2838: TYPE_ARG_TYPES (TREE_TYPE (sender)) = savarg;
2839: TREE_TYPE (TREE_TYPE (sender)) = savret;
2840: return retval;
2841: }
2842: #else /* not NEXT_OBJC_RUNTIME */
2843: /* This is the portable way.
2844: First call the lookup function to get a pointer to the method,
2845: then cast the pointer, then call it with the method arguments. */
2846: tree method;
2847:
2848: /* Avoid trouble since we may evaluate each of these twice. */
2849: object = save_expr (object);
2850: selector = save_expr (selector);
2851:
2852: method
2853: = build_function_call (sender,
2854: tree_cons (NULLT, lookup_object,
2855: tree_cons (NULLT, selector, NULLT)));
2856:
2857: /* If we have a method prototype, construct the data type this method needs,
2858: and cast what we got from SENDER into a pointer to that type. */
2859: if (method_prototype)
2860: {
2861: tree arglist = get_arg_type_list (method_prototype, METHOD_REF, super_flag);
2862: tree valtype = groktypename (TREE_TYPE (method_prototype));
2863: tree fake_function_type = build_function_type (valtype, arglist);
2864: TREE_TYPE (method) = build_pointer_type (fake_function_type);
2865: }
2866: else
2867: {
2868: TREE_TYPE (method)
2869: = build_pointer_type (build_function_type (ptr_type_node, NULLT));
2870: }
2871: /* Pass the object to the method. */
2872: return build_function_call (method,
2873: tree_cons (NULLT, object,
2874: tree_cons (NULLT, selector,
2875: method_params)));
2876: #endif /* not NEXT_OBJC_RUNTIME */
2877: }
2878:
2879: tree
2880: build_selector_expr (selnamelist)
2881: tree selnamelist;
2882: {
2883: tree selname;
2884: int selTransTbl_index;
2885:
2886: if (!doing_objc_thang)
2887: fatal ("Objective-C text in C source file");
2888:
2889: /* obtain the full selector name */
2890: if (TREE_CODE (selnamelist) == IDENTIFIER_NODE)
2891: /* a unary selector */
2892: selname = selnamelist;
2893: else if (TREE_CODE (selnamelist) == TREE_LIST)
2894: selname = build_keyword_selector (selnamelist);
2895:
2896: selTransTbl_index = add_selector_reference (selname);
2897:
2898: #ifndef OBJC_NONUNIQUE_SELECTORS
2899: return build_selector_reference (selTransTbl_index);
2900: #else
2901: /* synthesize a reference into the selector translation table */
2902: return build_array_ref (_OBJC_SELECTOR_REFERENCES_decl,
2903: build_int_2 (selTransTbl_index, 0));
2904: #endif
2905: }
2906:
2907: tree
2908: build_encode_expr (type)
2909: tree type;
2910: {
2911: if (!doing_objc_thang)
2912: fatal ("Objective-C text in C source file");
2913:
2914: if (!utlbuf)
2915: utlbuf = (char *)xmalloc (BUFSIZE);
2916: bzero (utlbuf, BUFSIZE);
2917:
2918: encode_type (type, utlbuf, OBJC_ENCODE_INLINE_DEFS);
2919:
2920: /* synthesize a string that represents the encoded struct/union */
2921: return my_build_string (strlen (utlbuf) + 1, utlbuf);
2922: }
2923:
2924: tree
2925: build_ivar_reference (id)
2926: tree id;
2927: {
2928: if (TREE_CODE (method_context) == CLASS_METHOD_DECL)
2929: TREE_TYPE (self_decl) = instance_type; /* cast */
2930:
2931: return build_component_ref (build_indirect_ref (self_decl, "->"), id);
2932: }
2933:
2934: #define HASH_ALLOC_LIST_SIZE 170
2935: #define ATTR_ALLOC_LIST_SIZE 170
2936: #define SIZEHASHTABLE 257
2937: #define HASHFUNCTION(key) ((int)key >> 2) /* divide by 4 */
2938:
2939: static void
2940: hash_init ()
2941: {
2942: nst_method_hash_list = (hash *)xmalloc (SIZEHASHTABLE * sizeof (hash));
2943: cls_method_hash_list = (hash *)xmalloc (SIZEHASHTABLE * sizeof (hash));
2944:
2945: if (!nst_method_hash_list || !cls_method_hash_list)
2946: perror ("unable to allocate space in objc-tree.c");
2947: else
2948: {
2949: int i;
2950:
2951: for (i = 0; i < SIZEHASHTABLE; i++)
2952: {
2953: nst_method_hash_list[i] = 0;
2954: cls_method_hash_list[i] = 0;
2955: }
2956: }
2957: }
2958:
2959: static void
2960: hash_enter (hashlist, method)
2961: hash *hashlist;
2962: tree method;
2963: {
2964: static hash hash_alloc_list = 0;
2965: static int hash_alloc_index = 0;
2966: hash obj;
2967: int slot = HASHFUNCTION (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
2968:
2969: if (!hash_alloc_list || hash_alloc_index >= HASH_ALLOC_LIST_SIZE)
2970: {
2971: hash_alloc_index = 0;
2972: hash_alloc_list = (hash)xmalloc (sizeof (struct hashedEntry) *
2973: HASH_ALLOC_LIST_SIZE);
2974: if (!hash_alloc_list)
2975: perror ("unable to allocate in objc-tree.c");
2976: }
2977: obj = &hash_alloc_list[hash_alloc_index++];
2978: obj->list = 0;
2979: obj->next = hashlist[slot];
2980: obj->key = method;
2981:
2982: hashlist[slot] = obj; /* append to front */
2983: }
2984:
2985: static hash
2986: hash_lookup (hashlist, sel_name)
2987: hash *hashlist;
2988: tree sel_name;
2989: {
2990: hash target;
2991:
2992: target = hashlist[HASHFUNCTION (sel_name) % SIZEHASHTABLE];
2993:
2994: while (target)
2995: {
2996: if (sel_name == METHOD_SEL_NAME (target->key))
2997: return target;
2998:
2999: target = target->next;
3000: }
3001: return 0;
3002: }
3003:
3004: static void
3005: hash_add_attr (entry, value)
3006: hash entry;
3007: tree value;
3008: {
3009: static attr attr_alloc_list = 0;
3010: static int attr_alloc_index = 0;
3011: attr obj;
3012:
3013: if (!attr_alloc_list || attr_alloc_index >= ATTR_ALLOC_LIST_SIZE)
3014: {
3015: attr_alloc_index = 0;
3016: attr_alloc_list = (attr)xmalloc (sizeof (struct hashedAttribute) *
3017: ATTR_ALLOC_LIST_SIZE);
3018: if (!attr_alloc_list)
3019: perror ("unable to allocate in objc-tree.c");
3020: }
3021: obj = &attr_alloc_list[attr_alloc_index++];
3022: obj->next = entry->list;
3023: obj->value = value;
3024:
3025: entry->list = obj; /* append to front */
3026: }
3027:
3028: static tree
3029: lookup_method (mchain, method)
3030: tree mchain;
3031: tree method;
3032: {
3033: tree key;
3034:
3035: if (TREE_CODE (method) == IDENTIFIER_NODE)
3036: key = method;
3037: else
3038: key = METHOD_SEL_NAME (method);
3039:
3040: while (mchain)
3041: {
3042: if (METHOD_SEL_NAME (mchain) == key)
3043: return mchain;
3044: mchain = TREE_CHAIN (mchain);
3045: }
3046: return NULLT;
3047: }
3048:
3049: static tree
3050: lookup_instance_method_static (interface, ident)
3051: tree interface;
3052: tree ident;
3053: {
3054: tree inter = interface;
3055: tree chain = CLASS_NST_METHODS (inter);
3056: tree meth = NULLT;
3057:
3058: do
3059: {
3060: if (meth = lookup_method (chain, ident))
3061: return meth;
3062:
3063: if (CLASS_CATEGORY_LIST (inter))
3064: {
3065: tree category = CLASS_CATEGORY_LIST (inter);
3066: chain = CLASS_NST_METHODS (category);
3067:
3068: do
3069: {
3070: if (meth = lookup_method (chain, ident))
3071: return meth;
3072:
3073: if (category = CLASS_CATEGORY_LIST (category))
3074: chain = CLASS_NST_METHODS (category);
3075: }
3076: while (category);
3077: }
3078:
3079: if (inter = lookup_interface (CLASS_SUPER_NAME (inter)))
3080: chain = CLASS_NST_METHODS (inter);
3081: }
3082: while (inter);
3083:
3084: return meth;
3085: }
3086:
3087: static tree
3088: lookup_class_method_static (interface, ident)
3089: tree interface;
3090: tree ident;
3091: {
3092: tree inter = interface;
3093: tree chain = CLASS_CLS_METHODS (inter);
3094: tree meth = NULLT;
3095:
3096: do
3097: {
3098: if (meth = lookup_method (chain, ident))
3099: return meth;
3100:
3101: if (CLASS_CATEGORY_LIST (inter))
3102: {
3103: tree category = CLASS_CATEGORY_LIST (inter);
3104: chain = CLASS_CLS_METHODS (category);
3105:
3106: do
3107: {
3108: if (meth = lookup_method (chain, ident))
3109: return meth;
3110:
3111: if (category = CLASS_CATEGORY_LIST (category))
3112: chain = CLASS_CLS_METHODS (category);
3113: }
3114: while (category);
3115: }
3116:
3117: if (inter = lookup_interface (CLASS_SUPER_NAME (inter)))
3118: chain = CLASS_CLS_METHODS (inter);
3119: }
3120: while (inter);
3121:
3122: return meth;
3123: }
3124:
3125: tree
3126: add_class_method (class, method)
3127: tree class;
3128: tree method;
3129: {
3130: tree mth;
3131: hash hsh;
3132:
3133: if (!(mth = lookup_method (CLASS_CLS_METHODS (class), method)))
3134: {
3135: /* put method on list in reverse order */
3136: TREE_CHAIN (method) = CLASS_CLS_METHODS (class);
3137: CLASS_CLS_METHODS (class) = method;
3138: }
3139: else
3140: {
3141: if (TREE_CODE (class) == IMPLEMENTATION_TYPE)
3142: error ("duplicate definition of class method `%s'.",
3143: IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
3144: else
3145: {
3146: /* check types, if different complain */
3147: if (!comp_proto_with_proto (method, mth))
3148: error ("duplicate declaration of class method `%s'.",
3149: IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
3150: }
3151: }
3152:
3153: if (!(hsh = hash_lookup (cls_method_hash_list, METHOD_SEL_NAME (method))))
3154: {
3155: /* install on a global chain */
3156: hash_enter (cls_method_hash_list, method);
3157: }
3158: else
3159: {
3160: /* check types, if different add to a list */
3161: if (!comp_proto_with_proto (method, hsh->key))
3162: hash_add_attr (hsh, method);
3163: }
3164: return method;
3165: }
3166:
3167: tree
3168: add_instance_method (class, method)
3169: tree class;
3170: tree method;
3171: {
3172: tree mth;
3173: hash hsh;
3174:
3175: if (!(mth = lookup_method (CLASS_NST_METHODS (class), method)))
3176: {
3177: /* put method on list in reverse order */
3178: TREE_CHAIN (method) = CLASS_NST_METHODS (class);
3179: CLASS_NST_METHODS (class) = method;
3180: }
3181: else
3182: {
3183: if (TREE_CODE (class) == IMPLEMENTATION_TYPE)
3184: error ("duplicate definition of instance method `%s'.",
3185: IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
3186: else
3187: {
3188: /* check types, if different complain */
3189: if (!comp_proto_with_proto (method, mth))
3190: error ("duplicate declaration of instance method `%s'.",
3191: IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
3192: }
3193: }
3194:
3195: if (!(hsh = hash_lookup (nst_method_hash_list, METHOD_SEL_NAME (method))))
3196: {
3197: /* install on a global chain */
3198: hash_enter (nst_method_hash_list, method);
3199: }
3200: else
3201: {
3202: /* check types, if different add to a list */
3203: if (!comp_proto_with_proto (method, hsh->key))
3204: hash_add_attr (hsh, method);
3205: }
3206: return method;
3207: }
3208:
3209: static tree
3210: add_class (class)
3211: tree class;
3212: {
3213: /* put interfaces on list in reverse order */
3214: TREE_CHAIN (class) = interface_chain;
3215: interface_chain = class;
3216: return interface_chain;
3217: }
3218:
3219: static void
3220: add_category (class, category)
3221: tree class;
3222: tree category;
3223: {
3224: /* put categories on list in reverse order */
3225: CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
3226: CLASS_CATEGORY_LIST (class) = category;
3227: }
3228:
3229: /* called after parsing each instance variable declaration. Necessary to
3230: * preserve typedefs and implement public/private...
3231: */
3232: tree
3233: add_instance_variable (class, public, declarator, declspecs, width)
3234: tree class;
3235: int public;
3236: tree declarator;
3237: tree declspecs;
3238: tree width;
3239: {
3240: tree field_decl, raw_decl;
3241:
3242: raw_decl = build_tree_list (declspecs /*purpose*/, declarator/*value*/);
3243:
3244: if (CLASS_RAW_IVARS (class))
3245: chainon (CLASS_RAW_IVARS (class), raw_decl);
3246: else
3247: CLASS_RAW_IVARS (class) = raw_decl;
3248:
3249: field_decl = grokfield (input_filename, lineno,
3250: declarator, declspecs, width);
3251:
3252: /* overload the public attribute, it is not used for FIELD_DECL's */
3253: if (public)
3254: TREE_PUBLIC (field_decl) = 1;
3255:
3256: if (CLASS_IVARS (class))
3257: chainon (CLASS_IVARS (class), field_decl);
3258: else
3259: CLASS_IVARS (class) = field_decl;
3260:
3261: return class;
3262: }
3263:
3264: tree
3265: is_ivar (decl_chain, ident)
3266: tree decl_chain;
3267: tree ident;
3268: {
3269: for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain))
3270: if (DECL_NAME (decl_chain) == ident)
3271: return decl_chain;
3272: return NULL_TREE;
3273: }
3274:
3275: /* we have an instance variable reference, check to see if it is public...*/
3276:
3277: int
3278: is_public (expr, identifier)
3279: tree expr;
3280: tree identifier;
3281: {
3282: tree basetype = TREE_TYPE (expr);
3283: enum tree_code code = TREE_CODE (basetype);
3284: tree decl;
3285:
3286: if (code == RECORD_TYPE)
3287: {
3288: if (TREE_STATIC_TEMPLATE (basetype))
3289: {
3290: if (decl = is_ivar (TYPE_FIELDS (basetype), identifier))
3291: {
3292: /* important diffence between the Stepstone translator:
3293:
3294: all instance variables should be public within the context
3295: of the implementation...
3296: */
3297: if (implementation_context)
3298: {
3299: if ((TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE
3300: && CLASS_NAME (implementation_context) == TYPE_NAME (basetype))
3301: || (TREE_CODE (implementation_context) == CATEGORY_TYPE
3302: && CLASS_NAME (implementation_context) == TYPE_NAME (basetype)))
3303: return 1;
3304: }
3305:
3306: if (TREE_PUBLIC (decl))
3307: return 1;
3308:
3309: error ("instance variable `%s' is declared private",
3310: IDENTIFIER_POINTER (identifier));
3311: return 0;
3312: }
3313: }
3314: else if (implementation_context && (basetype == objc_object_reference))
3315: {
3316: TREE_TYPE (expr) = _PRIVATE_record;
3317: if (extra_warnings)
3318: {
3319: warning ("static access to object of type `id'");
3320: warning ("please change to type `%s *'",
3321: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)));
3322: }
3323: }
3324: }
3325: return 1;
3326: }
3327:
3328: /* implement @defs (<classname>) within struct bodies. */
3329:
3330: tree
3331: get_class_ivars (interface)
3332: tree interface;
3333: {
3334: if (!doing_objc_thang)
3335: fatal ("Objective-C text in C source file");
3336:
3337: return build_ivar_chain (interface);
3338: }
3339:
3340: tree
3341: get_class_reference (interface)
3342: tree interface;
3343: {
3344: tree params;
3345:
3346: add_class_reference (CLASS_NAME (interface));
3347:
3348: params = build_tree_list (NULLT,
3349: my_build_string (IDENTIFIER_LENGTH (CLASS_NAME (interface)) + 1,
3350: IDENTIFIER_POINTER (CLASS_NAME (interface))));
3351:
3352: return build_function_call (objc_getClass_decl, params);
3353: }
3354:
3355: /* make sure all entries in "chain" are also in "list" */
3356:
3357: static void
3358: check_methods (chain, list, mtype)
3359: tree chain;
3360: tree list;
3361: int mtype;
3362: {
3363: int first = 1;
3364:
3365: while (chain)
3366: {
3367: if (!lookup_method (list, chain))
3368: {
3369: if (first)
3370: {
3371: if (TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE)
3372: warning ("incomplete implementation of class `%s'",
3373: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)));
3374: else if (TREE_CODE (implementation_context) == CATEGORY_TYPE)
3375: warning ("incomplete implementation of category `%s'",
3376: IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)));
3377: first = 0;
3378: }
3379: warning ("method definition for `%c%s' not found",
3380: mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain)));
3381: }
3382: chain = TREE_CHAIN (chain);
3383: }
3384: }
3385:
3386: tree
3387: start_class (code, class_name, super_name)
3388: enum tree_code code;
3389: tree class_name;
3390: tree super_name;
3391: {
3392: tree class;
3393:
3394: if (!doing_objc_thang)
3395: fatal ("Objective-C text in C source file");
3396:
3397: class = make_node (code);
3398:
3399: CLASS_NAME (class) = class_name;
3400: CLASS_SUPER_NAME (class) = super_name;
3401: CLASS_CLS_METHODS (class) = NULL_TREE;
3402:
3403: if (code == IMPLEMENTATION_TYPE)
3404: {
3405: /* pre-build the following entities - for speed/convenience. */
3406: if (!self_id)
3407: self_id = get_identifier ("self");
3408: if (!_cmd_id)
3409: _cmd_id = get_identifier ("_cmd");
3410:
3411: if (!objc_super_template)
3412: objc_super_template = build_super_template ();
3413:
3414: method_slot = 0; /* reset for multiple classes per file */
3415:
3416: implementation_context = class;
3417:
3418: /* lookup the interface for this implementation. */
3419:
3420: if (!(implementation_template = lookup_interface (class_name)))
3421: {
3422: warning ("Cannot find interface declaration for `%s'",
3423: IDENTIFIER_POINTER (class_name));
3424: add_class (implementation_template = implementation_context);
3425: }
3426:
3427: /* if a super class has been specified in the implementation,
3428: insure it conforms to the one specified in the interface */
3429:
3430: if (super_name
3431: && (super_name != CLASS_SUPER_NAME (implementation_template)))
3432: {
3433: error ("conflicting super class name `%s'",
3434: IDENTIFIER_POINTER (super_name));
3435: error ("previous declaration of `%s'",
3436: IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template)));
3437: }
3438: }
3439: else if (code == INTERFACE_TYPE)
3440: {
3441: if (lookup_interface (class_name))
3442: warning ("duplicate interface declaration for class `%s'",
3443: IDENTIFIER_POINTER (class_name));
3444: else
3445: add_class (class);
3446: }
3447: else if (code == PROTOCOL_TYPE)
3448: {
3449: tree class_category_is_assoc_with;
3450:
3451: /* for a category, class_name is really the name of the class that
3452: the following set of methods will be associated with...we must
3453: find the interface so that can derive the objects template */
3454:
3455: if (!(class_category_is_assoc_with = lookup_interface (class_name)))
3456: {
3457: error ("Cannot find interface declaration for `%s'",
3458: IDENTIFIER_POINTER (class_name));
3459: exit (1);
3460: }
3461: else
3462: add_category (class_category_is_assoc_with, class);
3463: }
3464: else if (code == CATEGORY_TYPE)
3465: {
3466: /* pre-build the following entities - for speed/convenience. */
3467: if (!self_id)
3468: self_id = get_identifier ("self");
3469: if (!_cmd_id)
3470: _cmd_id = get_identifier ("_cmd");
3471:
3472: if (!objc_super_template)
3473: objc_super_template = build_super_template ();
3474:
3475: method_slot = 0; /* reset for multiple classes per file */
3476:
3477: implementation_context = class;
3478:
3479: /* for a category, class_name is really the name of the class that
3480: the following set of methods will be associated with...we must
3481: find the interface so that can derive the objects template */
3482:
3483: if (!(implementation_template = lookup_interface (class_name)))
3484: {
3485: error ("Cannot find interface declaration for `%s'",
3486: IDENTIFIER_POINTER (class_name));
3487: exit (1);
3488: }
3489: }
3490: return class;
3491: }
3492:
3493: tree
3494: continue_class (class)
3495: tree class;
3496: {
3497: if (TREE_CODE (class) == IMPLEMENTATION_TYPE
3498: || TREE_CODE (class) == CATEGORY_TYPE)
3499: {
3500: struct imp_entry *impEntry;
3501: tree ivar_context;
3502:
3503: /* check consistency of the instance variables. */
3504:
3505: if (CLASS_IVARS (class))
3506: check_ivars (implementation_template, class);
3507:
3508: /* code generation */
3509:
3510: ivar_context = build_private_template (implementation_template);
3511:
3512: if (!objc_class_template)
3513: build_class_template ();
3514:
3515: if (!(impEntry = (struct imp_entry *)xmalloc (sizeof (struct imp_entry))))
3516: perror ("unable to allocate in objc-tree.c");
3517:
3518: impEntry->next = imp_list;
3519: impEntry->imp_context = class;
3520: impEntry->imp_template = implementation_template;
3521:
3522: synth_forward_declarations ();
3523: impEntry->class_decl = _OBJC_CLASS_decl;
3524: impEntry->meta_decl = _OBJC_METACLASS_decl;
3525:
3526: /* append to front and increment count */
3527: imp_list = impEntry;
3528: if (TREE_CODE (class) == IMPLEMENTATION_TYPE)
3529: imp_count++;
3530: else
3531: cat_count++;
3532:
3533: return ivar_context;
3534: }
3535: else if (TREE_CODE (class) == INTERFACE_TYPE)
3536: {
3537: tree record = xref_tag (RECORD_TYPE, CLASS_NAME (class));
3538:
3539: if (!TYPE_FIELDS (record))
3540: {
3541: finish_struct (record, build_ivar_chain (class));
3542: CLASS_STATIC_TEMPLATE (class) = record;
3543:
3544: /* mark this record as a class template - for static typing */
3545: TREE_STATIC_TEMPLATE (record) = 1;
3546: }
3547: return NULLT;
3548: }
3549: else
3550: return error_mark_node;
3551: }
3552:
3553: /*
3554: * this is called once we see the "@end" in an interface/implementation.
3555: */
3556: void
3557: finish_class (class)
3558: tree class;
3559: {
3560: if (TREE_CODE (class) == IMPLEMENTATION_TYPE)
3561: {
3562: /* all code generation is done in finish_objc */
3563:
3564: if (implementation_template != implementation_context)
3565: {
3566: /* ensure that all method listed in the interface contain bodies! */
3567: check_methods (CLASS_CLS_METHODS (implementation_template),
3568: CLASS_CLS_METHODS (implementation_context), '+');
3569: check_methods (CLASS_NST_METHODS (implementation_template),
3570: CLASS_NST_METHODS (implementation_context), '-');
3571: }
3572: }
3573: else if (TREE_CODE (class) == CATEGORY_TYPE)
3574: {
3575: tree category = CLASS_CATEGORY_LIST (implementation_template);
3576:
3577: /* find the category interface from the class it is associated with */
3578: while (category)
3579: {
3580: if (CLASS_SUPER_NAME (class) == CLASS_SUPER_NAME (category))
3581: break;
3582: category = CLASS_CATEGORY_LIST (category);
3583: }
3584:
3585: if (category)
3586: {
3587: /* ensure that all method listed in the interface contain bodies! */
3588: check_methods (CLASS_CLS_METHODS (category),
3589: CLASS_CLS_METHODS (implementation_context), '+');
3590: check_methods (CLASS_NST_METHODS (category),
3591: CLASS_NST_METHODS (implementation_context), '-');
3592: }
3593: }
3594: else if (TREE_CODE (class) == INTERFACE_TYPE)
3595: {
3596: tree decl_specs;
3597:
3598: /* extern struct objc_object *_<my_name>; */
3599:
3600: sprintf (utlbuf, "_%s", IDENTIFIER_POINTER (CLASS_NAME (class)));
3601:
3602: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_EXTERN]);
3603: decl_specs = tree_cons (NULLT, objc_object_reference, decl_specs);
3604: define_decl (build1 (INDIRECT_REF, NULLT, get_identifier (utlbuf)), decl_specs);
3605: }
3606: }
3607:
3608: static void
3609: encode_pointer (type, str, format)
3610: tree type;
3611: char *str;
3612: int format;
3613: {
3614: tree pointer_to = TREE_TYPE (type);
3615:
3616: if (TREE_CODE (pointer_to) == RECORD_TYPE)
3617: {
3618: if (TYPE_NAME (pointer_to)
3619: && TREE_CODE (TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
3620: {
3621: char *name = IDENTIFIER_POINTER (TYPE_NAME (pointer_to));
3622:
3623: if ((strcmp (name, TAG_OBJECT) == 0) || /* '@' */
3624: (TREE_STATIC_TEMPLATE (pointer_to)))
3625: {
3626: strcat (str, "@");
3627: return;
3628: }
3629: else if (strcmp (name, TAG_CLASS) == 0) /* '#' */
3630: {
3631: strcat (str, "#");
3632: return;
3633: }
3634: #ifndef OBJC_INT_SELECTORS
3635: else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */
3636: {
3637: strcat (str, ":");
3638: return;
3639: }
3640: #endif /* OBJC_INT_SELECTORS */
3641: }
3642: }
3643: else if (TREE_CODE (pointer_to) == INTEGER_TYPE
3644: && TYPE_MODE (pointer_to) == QImode)
3645: {
3646: strcat (str, "*");
3647: return;
3648: }
3649:
3650: /* we have a type that does not get special treatment... */
3651:
3652: /* NeXT extension */
3653: strcat (str, "^");
3654: encode_type (pointer_to, str, format);
3655: }
3656:
3657: static void
3658: encode_array (type, str, format)
3659: tree type;
3660: char *str;
3661: int format;
3662: {
3663: tree anIntCst = TYPE_SIZE (type);
3664: tree array_of = TREE_TYPE (type);
3665:
3666: /* An incomplete array is treated like a pointer. */
3667: if (anIntCst == NULL)
3668: {
3669: /* split for obvious reasons. North-Keys 30 Mar 1991 */
3670: encode_pointer (type, str, format);
3671: return;
3672: }
3673:
3674: sprintf (str + strlen (str), "[%d",
3675: TREE_INT_CST_LOW (anIntCst)
3676: / TREE_INT_CST_LOW (TYPE_SIZE (array_of)));
3677: encode_type (array_of, str, format);
3678: strcat (str, "]");
3679: return;
3680: }
3681:
3682: static void
3683: encode_aggregate (type, str, format)
3684: tree type;
3685: char *str;
3686: int format;
3687: {
3688: enum tree_code code = TREE_CODE (type);
3689:
3690: switch (code)
3691: {
3692: case RECORD_TYPE:
3693: {
3694: if (str[strlen (str)-1] == '^')
3695: {
3696: /* we have a reference - this is a NeXT extension */
3697: if (TYPE_NAME (type)
3698: && (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE))
3699: sprintf (str + strlen (str), "{%s}",
3700: IDENTIFIER_POINTER (TYPE_NAME (type)));
3701: else /* we have an untagged structure or a typedef */
3702: sprintf (str + strlen (str), "{?}");
3703: }
3704: else
3705: {
3706: tree fields = TYPE_FIELDS (type);
3707:
3708: if (format == OBJC_ENCODE_INLINE_DEFS)
3709: {
3710: strcat (str, "{");
3711: for ( ; fields; fields = TREE_CHAIN (fields))
3712: encode_field_decl (fields, str, format);
3713: strcat (str, "}");
3714: }
3715: else
3716: {
3717: if (TYPE_NAME (type)
3718: && (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE))
3719: sprintf (str + strlen (str), "{%s}",
3720: IDENTIFIER_POINTER (TYPE_NAME (type)));
3721: else /* we have an untagged structure or a typedef */
3722: sprintf (str + strlen (str), "{?}");
3723: }
3724: }
3725: break;
3726: }
3727: case UNION_TYPE:
3728: {
3729: if (str[strlen (str)-1] == '^')
3730: {
3731: if (TYPE_NAME (type)
3732: && (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE))
3733: /* we have a reference - this is a NeXT extension */
3734: sprintf (str + strlen (str), "(%s)",
3735: IDENTIFIER_POINTER (TYPE_NAME (type)));
3736: else /* we have an untagged structure */
3737: sprintf (str + strlen (str), "(?)");
3738: }
3739: else
3740: {
3741: tree fields = TYPE_FIELDS (type);
3742:
3743: if (format == OBJC_ENCODE_INLINE_DEFS)
3744: {
3745: strcat (str, "(");
3746: for ( ; fields; fields = TREE_CHAIN (fields))
3747: encode_field_decl (fields, str, format);
3748: strcat (str, ")");
3749: }
3750: else
3751: {
3752: if (TYPE_NAME (type) &&
3753: (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE))
3754: /* we have a reference - this is a NeXT extension */
3755: sprintf (str + strlen (str), "(%s)",
3756: IDENTIFIER_POINTER (TYPE_NAME (type)));
3757: else /* we have an untagged structure */
3758: sprintf (str + strlen (str), "(?)");
3759: }
3760: }
3761: break;
3762: }
3763: case ENUMERAL_TYPE:
3764: strcat (str, "i");
3765: break;
3766: }
3767: }
3768:
3769: /*
3770: * support bitfields, the current version of Objective-C does not support
3771: * them. the string will consist of one or more "b:n"'s where n is an
3772: * integer describing the width of the bitfield. Currently, classes in
3773: * the kit implement a method "-(char *)describeBitfieldStruct:" that
3774: * simulates this...if they do not implement this method, the archiver
3775: * assumes the bitfield is 16 bits wide (padded if necessary) and packed
3776: * according to the GNU compiler. After looking at the "kit", it appears
3777: * that all classes currently rely on this default behavior, rather than
3778: * hand generating this string (which is tedious).
3779: */
3780: static void
3781: encode_bitfield (width, str, format)
3782: int width;
3783: char *str;
3784: int format;
3785: {
3786: sprintf (str + strlen (str), "b%d", width);
3787: }
3788:
3789: /*
3790: * format will be:
3791: *
3792: * OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS
3793: */
3794: static void
3795: encode_type (type, str, format)
3796: tree type;
3797: char *str;
3798: int format;
3799: {
3800: enum tree_code code = TREE_CODE (type);
3801:
3802: if (code == INTEGER_TYPE)
3803: {
3804: if (TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) == 0)
3805: {
3806: /* unsigned integer types */
3807:
3808: if (TYPE_MODE (type) == QImode) /* 'C' */
3809: strcat (str, "C");
3810: else if (TYPE_MODE (type) == HImode) /* 'S' */
3811: strcat (str, "S");
3812: else if (TYPE_MODE (type) == SImode)
3813: {
3814: if (type == long_unsigned_type_node)
3815: strcat (str, "L"); /* 'L' */
3816: else
3817: strcat (str, "I"); /* 'I' */
3818: }
3819: }
3820: else /* signed integer types */
3821: {
3822: if (TYPE_MODE (type) == QImode) /* 'c' */
3823: strcat (str, "c");
3824: else if (TYPE_MODE (type) == HImode) /* 's' */
3825: strcat (str, "s");
3826: else if (TYPE_MODE (type) == SImode) /* 'i' */
3827: {
3828: if (type == long_integer_type_node)
3829: strcat (str, "l"); /* 'l' */
3830: else
3831: strcat (str, "i"); /* 'i' */
3832: }
3833: }
3834: }
3835: else if (code == REAL_TYPE)
3836: {
3837: /* floating point types */
3838:
3839: if (TYPE_MODE (type) == SFmode) /* 'f' */
3840: strcat (str, "f");
3841: else if (TYPE_MODE (type) == DFmode
3842: || TYPE_MODE (type) == TFmode) /* 'd' */
3843: strcat (str, "d");
3844: }
3845:
3846: else if (code == VOID_TYPE) /* 'v' */
3847: strcat (str, "v");
3848:
3849: else if (code == ARRAY_TYPE)
3850: encode_array (type, str, format);
3851:
3852: else if (code == POINTER_TYPE)
3853: encode_pointer (type, str, format);
3854:
3855: else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
3856: encode_aggregate (type, str, format);
3857:
3858: else if (code == FUNCTION_TYPE) /* '?' */
3859: strcat (str, "?");
3860: }
3861:
3862: static void
3863: encode_field_decl (field_decl, str, format)
3864: tree field_decl;
3865: char *str;
3866: int format;
3867: {
3868: if (DECL_BIT_FIELD (field_decl))
3869: encode_bitfield (DECL_FRAME_SIZE (field_decl), str, format);
3870: else
3871: encode_type (TREE_TYPE (field_decl), str, format);
3872: }
3873:
3874: static tree
3875: expr_last (complex_expr)
3876: tree complex_expr;
3877: {
3878: tree next;
3879:
3880: if (complex_expr)
3881: while (next = TREE_OPERAND (complex_expr, 0))
3882: complex_expr = next;
3883: return complex_expr;
3884: }
3885:
3886: /* The selector of the current method,
3887: or NULL if we aren't compiling a method. */
3888:
3889: tree
3890: maybe_objc_method_name (decl)
3891: tree decl;
3892: {
3893: if (method_context)
3894: return METHOD_SEL_NAME (method_context);
3895: else
3896: return 0;
3897: }
3898:
3899: /*
3900: * Transform a method definition into a function definition as follows:
3901: *
3902: * - synthesize the first two arguments, "self" and "_cmd".
3903: */
3904:
3905: void
3906: start_method_def (method)
3907: tree method;
3908: {
3909: tree decl_specs;
3910:
3911: /* required to implement _msgSuper () */
3912: method_context = method;
3913: _OBJC_SUPER_decl = NULLT;
3914:
3915: pushlevel (0); /* must be called BEFORE "start_function ()" */
3916:
3917: /* generate prototype declarations for arguments..."new-style" */
3918:
3919: if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL)
3920: decl_specs = build_tree_list (NULLT, _PRIVATE_record);
3921: else
3922: /* really a `struct objc_class *'...however we allow people to
3923: assign to self...which changes its type midstream.
3924: */
3925: decl_specs = build_tree_list (NULLT, objc_object_reference);
3926:
3927: push_parm_decl (build_tree_list (decl_specs,
3928: build1 (INDIRECT_REF, NULLT, self_id)));
3929:
3930: #ifdef OBJC_INT_SELECTORS
3931: decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_UNSIGNED]);
3932: decl_specs = tree_cons (NULLT, ridpointers[(int) RID_INT], decl_specs);
3933: push_parm_decl (build_tree_list (decl_specs, _cmd_id));
3934: #else /* not OBJC_INT_SELECTORS */
3935: decl_specs = build_tree_list (NULLT,
3936: xref_tag (RECORD_TYPE,
3937: get_identifier (TAG_SELECTOR)));
3938: push_parm_decl (build_tree_list (decl_specs,
3939: build1 (INDIRECT_REF, NULLT, _cmd_id)));
3940: #endif /* not OBJC_INT_SELECTORS */
3941:
3942: /* generate argument delclarations if a keyword_decl */
3943: if (METHOD_SEL_ARGS (method))
3944: {
3945: tree arglist = METHOD_SEL_ARGS (method);
3946: do
3947: {
3948: tree arg_spec = TREE_PURPOSE (TREE_TYPE (arglist));
3949: tree arg_decl = TREE_VALUE (TREE_TYPE (arglist));
3950:
3951: if (arg_decl)
3952: {
3953: tree last_expr = expr_last (arg_decl);
3954:
3955: /* unite the abstract decl with its name */
3956: TREE_OPERAND (last_expr, 0) = KEYWORD_ARG_NAME (arglist);
3957: push_parm_decl (build_tree_list (arg_spec, arg_decl));
3958: /* unhook...restore the abstract declarator */
3959: TREE_OPERAND (last_expr, 0) = NULLT;
3960: }
3961: else
3962: push_parm_decl (build_tree_list (arg_spec, KEYWORD_ARG_NAME (arglist)));
3963:
3964: arglist = TREE_CHAIN (arglist);
3965: }
3966: while (arglist);
3967: }
3968:
3969: if (METHOD_ADD_ARGS (method) > (tree)1)
3970: {
3971: /* we have a variable length selector - in "prototype" format */
3972: tree akey = TREE_PURPOSE (METHOD_ADD_ARGS (method));
3973: while (akey)
3974: {
3975: /* this must be done prior to calling pushdecl (). pushdecl () is
3976: * going to change our chain on us...
3977: */
3978: tree nextkey = TREE_CHAIN (akey);
3979: pushdecl (akey);
3980: akey = nextkey;
3981: }
3982: }
3983: }
3984:
3985: static void
3986: error_with_method (message, mtype, method)
3987: char *message;
3988: char mtype;
3989: tree method;
3990: {
3991: count_error (0);
3992: fprintf (stderr, "%s:%d: ",
3993: DECL_SOURCE_FILE (method), DECL_SOURCE_LINE (method));
3994: bzero (errbuf, BUFSIZE);
3995: fprintf (stderr, "%s `%c%s'\n", message, mtype, gen_method_decl (method, errbuf));
3996: }
3997:
3998: static void
3999: warn_with_method (message, mtype, method)
4000: char *message;
4001: char mtype;
4002: tree method;
4003: {
4004: count_error (1);
4005: fprintf (stderr, "%s:%d: ",
4006: DECL_SOURCE_FILE (method), DECL_SOURCE_LINE (method));
4007: bzero (errbuf, BUFSIZE);
4008: fprintf (stderr, "%s `%c%s'\n", message, mtype, gen_method_decl (method, errbuf));
4009: }
4010:
4011: /* return 1 if `method' is consistent with `proto' */
4012:
4013: static int
4014: comp_method_with_proto (method, proto)
4015: tree method, proto;
4016: {
4017: static tree function_type = 0;
4018:
4019: /* create a function_type node once */
4020: if (!function_type)
4021: {
4022: struct obstack *ambient_obstack = current_obstack;
4023:
4024: current_obstack = &permanent_obstack;
4025: function_type = make_node (FUNCTION_TYPE);
4026: current_obstack = ambient_obstack;
4027: }
4028:
4029: /* install argument types - normally set by "build_function_type ()". */
4030: TYPE_ARG_TYPES (function_type) = get_arg_type_list (proto, METHOD_DEF, 0);
4031:
4032: /* install return type */
4033: TREE_TYPE (function_type) = groktypename (TREE_TYPE (proto));
4034:
4035: return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function_type);
4036: }
4037:
4038: /* return 1 if `proto1' is consistent with `proto2' */
4039:
4040: static int
4041: comp_proto_with_proto (proto1, proto2)
4042: tree proto1, proto2;
4043: {
4044: static tree function_type1 = 0, function_type2 = 0;
4045:
4046: /* create a couple function_type node's once */
4047: if (!function_type1)
4048: {
4049: struct obstack *ambient_obstack = current_obstack;
4050:
4051: current_obstack = &permanent_obstack;
4052: function_type1 = make_node (FUNCTION_TYPE);
4053: function_type2 = make_node (FUNCTION_TYPE);
4054: current_obstack = ambient_obstack;
4055: }
4056:
4057: /* install argument types - normally set by "build_function_type ()". */
4058: TYPE_ARG_TYPES (function_type1) = get_arg_type_list (proto1, METHOD_REF, 0);
4059: TYPE_ARG_TYPES (function_type2) = get_arg_type_list (proto2, METHOD_REF, 0);
4060:
4061: /* install return type */
4062: TREE_TYPE (function_type1) = groktypename (TREE_TYPE (proto1));
4063: TREE_TYPE (function_type2) = groktypename (TREE_TYPE (proto2));
4064:
4065: return comptypes (function_type1, function_type2);
4066: }
4067:
4068: /*
4069: * - generate an identifier for the function. the format is "_n_cls",
4070: * where 1 <= n <= nMethods, and cls is the name the implementation we
4071: * are processing.
4072: * - install the return type from the method declaration.
4073: * - if we have a prototype, check for type consistency.
4074: */
4075: static void
4076: really_start_method (method, parmlist)
4077: tree method, parmlist;
4078: {
4079: tree sc_spec, ret_spec, ret_decl, decl_specs;
4080: tree method_decl, method_id;
1.1.1.2 ! root 4081: char *buf;
1.1 root 4082:
4083: /* synth the storage class & assemble the return type */
4084: sc_spec = tree_cons (NULLT, ridpointers[(int) RID_STATIC], NULLT);
4085: ret_spec = TREE_PURPOSE (TREE_TYPE (method));
4086: decl_specs = chainon (sc_spec, ret_spec);
4087:
4088: if (TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE)
1.1.1.2 ! root 4089: {
! 4090: /* Make sure this is big enough for any plausible method label. */
! 4091: buf = (char *) alloca (50
! 4092: + strlen (IDENTIFIER_POINTER (METHOD_SEL_NAME (method)))
! 4093: + strlen (IDENTIFIER_POINTER (CLASS_NAME (implementation_context))));
1.1 root 4094: #ifdef OBJC_GEN_METHOD_LABEL
1.1.1.2 ! root 4095: OBJC_GEN_METHOD_LABEL (buf,
! 4096: TREE_CODE (method) == INSTANCE_METHOD_DECL,
! 4097: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)),
! 4098: NULL,
! 4099: IDENTIFIER_POINTER (METHOD_SEL_NAME (method)));
1.1 root 4100: #else
1.1.1.2 ! root 4101: sprintf (buf, "_%d_%s", ++method_slot,
! 4102: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)));
1.1 root 4103: #endif
1.1.1.2 ! root 4104: }
1.1 root 4105: else /* we have a category */
1.1.1.2 ! root 4106: {
! 4107: /* Make sure this is big enough for any plausible method label. */
! 4108: buf = (char *) alloca (50
! 4109: + strlen (IDENTIFIER_POINTER (METHOD_SEL_NAME (method)))
! 4110: + strlen (IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)))
! 4111: + strlen (IDENTIFIER_POINTER (CLASS_NAME (implementation_context))));
1.1 root 4112: #ifdef OBJC_GEN_METHOD_LABEL
1.1.1.2 ! root 4113: OBJC_GEN_METHOD_LABEL (buf,
! 4114: TREE_CODE (method) == INSTANCE_METHOD_DECL,
! 4115: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)),
! 4116: IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)),
! 4117: IDENTIFIER_POINTER (METHOD_SEL_NAME (method)));
1.1 root 4118: #else
1.1.1.2 ! root 4119: sprintf (buf, "_%d_%s_%s", ++method_slot,
! 4120: IDENTIFIER_POINTER (CLASS_NAME (implementation_context)),
! 4121: IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)));
1.1 root 4122: #endif
1.1.1.2 ! root 4123: }
1.1 root 4124:
4125: method_id = get_identifier (buf);
4126:
4127: method_decl = build_nt (CALL_EXPR, method_id, parmlist, NULLT);
4128:
4129: /* check the delclarator portion of the return type for the method */
4130: if (ret_decl = TREE_VALUE (TREE_TYPE (method)))
4131: {
4132: /*
4133: * unite the complex decl (specified in the abstract decl) with the
4134: * function decl just synthesized...(int *), (int (*)()), (int (*)[]).
4135: */
4136: tree save_expr = expr_last (ret_decl);
4137:
4138: TREE_OPERAND (save_expr, 0) = method_decl;
4139: method_decl = ret_decl;
4140: /* fool the parser into thinking it is starting a function */
4141: start_function (decl_specs, method_decl, 0);
4142: /* unhook...this has the effect of restoring the abstract declarator */
4143: TREE_OPERAND (save_expr, 0) = NULLT;
4144: }
4145: else
4146: {
4147: TREE_VALUE (TREE_TYPE (method)) = method_decl;
4148: /* fool the parser into thinking it is starting a function */
4149: start_function (decl_specs, method_decl, 0);
4150: /* unhook...this has the effect of restoring the abstract declarator */
4151: TREE_VALUE (TREE_TYPE (method)) = NULLT;
4152: }
4153:
4154: METHOD_DEFINITION (method) = current_function_decl;
4155:
4156: /* check consistency...start_function (), pushdecl (), duplicate_decls (). */
4157:
4158: if (implementation_template != implementation_context)
4159: {
4160: tree chain, proto;
4161:
4162: if (TREE_CODE (method) == INSTANCE_METHOD_DECL)
4163: chain = CLASS_NST_METHODS (implementation_template);
4164: else
4165: chain = CLASS_CLS_METHODS (implementation_template);
4166:
4167: if (proto = lookup_method (chain, METHOD_SEL_NAME (method)))
4168: {
4169: if (!comp_method_with_proto (method, proto))
4170: {
4171: fprintf (stderr, "%s: In method `%s'\n", input_filename,
4172: IDENTIFIER_POINTER (METHOD_SEL_NAME (method)));
4173: if (TREE_CODE (method) == INSTANCE_METHOD_DECL)
4174: {
4175: error_with_method ("conflicting types for", '-', method);
4176: error_with_method ("previous declaration of", '-', proto);
4177: }
4178: else
4179: {
4180: error_with_method ("conflicting types for", '+', method);
4181: error_with_method ("previous declaration of", '+', proto);
4182: }
4183: }
4184: }
4185: }
4186: }
4187:
4188: /*
4189: * the following routine is always called...this "architecture" is to
4190: * accommodate "old-style" variable length selectors.
4191: *
4192: * - a:a b:b // prototype ; id c; id d; // old-style
4193: */
4194: void
4195: continue_method_def ()
4196: {
4197: tree parmlist;
4198:
4199: if (METHOD_ADD_ARGS (method_context) == (tree)1)
4200: /*
4201: * we have a `, ...' immediately following the selector.
4202: */
4203: parmlist = get_parm_info (0);
4204: else
4205: parmlist = get_parm_info (1); /* place a `void_at_end' */
4206:
4207: /* set self_decl from the first argument...this global is used by
4208: * build_ivar_reference ().build_indirect_ref ().
4209: */
4210: self_decl = TREE_PURPOSE (parmlist);
4211:
4212: poplevel (0, 0, 0); /* must be called BEFORE "start_function ()" */
4213:
4214: really_start_method (method_context, parmlist);
4215:
4216: store_parm_decls (); /* must be called AFTER "start_function ()" */
4217: }
4218:
4219: void
4220: add_objc_decls ()
4221: {
4222: if (!_OBJC_SUPER_decl)
4223: _OBJC_SUPER_decl = start_decl (get_identifier (_TAG_SUPER),
4224: build_tree_list (NULLT, objc_super_template), 0);
4225:
4226: /* this prevents `unused variable' warnings when compiling with `-Wall' */
4227: TREE_USED (_OBJC_SUPER_decl) = 1;
4228: }
4229:
4230: /*
4231: * _n_Method (id self, SEL sel, ...)
4232: * {
4233: * struct objc_super _S;
4234: *
4235: * _msgSuper ((_S.self = self, _S.class = _cls, &_S), ...);
4236: * }
4237: */
4238: tree
4239: get_super_receiver ()
4240: {
4241: if (method_context)
4242: {
4243: tree super_expr, super_expr_list;
4244:
4245: /* set receiver to self */
4246: super_expr = build_component_ref (_OBJC_SUPER_decl, self_id);
4247: super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl);
4248: super_expr_list = build_tree_list (NULLT, super_expr);
4249:
4250: /* set class to begin searching */
4251: super_expr = build_component_ref (_OBJC_SUPER_decl, get_identifier ("class"));
4252:
4253: if (TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE)
4254: {
4255: /* [_cls, __cls]Super are "pre-built" in synth_foward_declarations () */
4256:
4257: if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL)
4258: super_expr = build_modify_expr (super_expr, NOP_EXPR, _clsSuper_ref);
4259: else
4260: super_expr = build_modify_expr (super_expr, NOP_EXPR, __clsSuper_ref);
4261: }
4262: else /* we have a category... */
4263: {
4264: tree params, super_name = CLASS_SUPER_NAME (implementation_template);
4265: tree funcCall;
4266:
4267: if (!super_name) /* Barf if super used in a category of Object. */
4268: {
4269: error("no super class declared in interface for `%s'",
4270: IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
4271: return error_mark_node;
4272: }
4273:
4274: add_class_reference (super_name);
4275:
4276: params = build_tree_list (NULLT,
4277: my_build_string (IDENTIFIER_LENGTH (super_name) + 1,
4278: IDENTIFIER_POINTER (super_name)));
4279:
4280: if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL)
4281: funcCall = build_function_call (objc_getClass_decl, params);
4282: else
4283: funcCall = build_function_call (objc_getMetaClass_decl, params);
4284:
4285: /* cast! */
4286: TREE_TYPE (funcCall) = TREE_TYPE (_clsSuper_ref);
4287: super_expr = build_modify_expr (super_expr, NOP_EXPR, funcCall);
4288: }
4289: chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
4290:
4291: super_expr = build_unary_op (ADDR_EXPR, _OBJC_SUPER_decl, 0);
4292: chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
4293:
4294: return build_compound_expr (super_expr_list);
4295: }
4296: else
4297: {
4298: error ("[super ...] must appear in a method context");
4299: return error_mark_node;
4300: }
4301: }
4302:
4303: static tree
4304: encode_method_def (func_decl)
4305: tree func_decl;
4306: {
4307: tree parms;
4308: int stack_size = 0;
4309:
4310: bzero (utlbuf, BUFSIZE);
4311:
4312: /* return type */
4313: encode_type (TREE_TYPE (TREE_TYPE (func_decl)), utlbuf,
4314: OBJC_ENCODE_DONT_INLINE_DEFS);
4315: /* stack size */
4316: for (parms = DECL_ARGUMENTS (func_decl); parms;
4317: parms = TREE_CHAIN (parms))
4318: stack_size += TREE_INT_CST_LOW (TYPE_SIZE (DECL_ARG_TYPE (parms)))
4319: / BITS_PER_UNIT;
4320:
4321: sprintf (&utlbuf[strlen (utlbuf)], "%d", stack_size);
4322:
4323: /* argument types */
4324: for (parms = DECL_ARGUMENTS (func_decl); parms;
4325: parms = TREE_CHAIN (parms))
4326: {
4327: int offset_in_bytes;
4328:
4329: /* type */
4330: encode_type (TREE_TYPE (parms), utlbuf, OBJC_ENCODE_DONT_INLINE_DEFS);
4331:
4332: /* compute offset */
4333: if (GET_CODE (DECL_INCOMING_RTL (parms)) == MEM)
4334: {
4335: rtx addr = XEXP (DECL_INCOMING_RTL (parms), 0);
4336:
4337: /* ??? Here we assume that the parm address is indexed
4338: off the frame pointer or arg pointer.
4339: If that is not true, we produce meaningless results,
4340: but do not crash. */
4341: if (GET_CODE (addr) == PLUS
4342: && GET_CODE (XEXP (addr, 1)) == CONST_INT)
4343: offset_in_bytes = INTVAL (XEXP (addr, 1));
4344: else
4345: offset_in_bytes = 0;
4346:
4347: /* This is the case where the parm is passed as an int or double
4348: and it is converted to a char, short or float and stored back
4349: in the parmlist. In this case, describe the parm
4350: with the variable's declared type, and adjust the address
4351: if the least significant bytes (which we are using) are not
4352: the first ones. */
4353: #if BYTES_BIG_ENDIAN
4354: if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms))
4355: offset_in_bytes += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms)))
4356: - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));
4357: #endif
4358: }
4359: else
4360: offset_in_bytes = 0;
4361:
4362: /* The "+ 4" is a total hack to account for the return pc and
4363: saved fp on the 68k. We should redefine this format! */
4364: sprintf (&utlbuf[strlen (utlbuf)], "%d", offset_in_bytes + 8);
4365: }
4366:
4367: return get_identifier (utlbuf);
4368: }
4369:
4370: void
4371: finish_method_def ()
4372: {
4373: METHOD_ENCODING (method_context) =
4374: encode_method_def (current_function_decl);
4375:
4376: finish_function (0);
4377:
4378: /* this must be done AFTER finish_function, since the optimizer may
4379: find "may be used before set" errors. */
4380: method_context = NULLT; /* required to implement _msgSuper () */
4381: }
4382:
4383: int
4384: lang_report_error_function (decl)
4385: tree decl;
4386: {
4387: if (method_context)
4388: {
4389: fprintf (stderr, "In method `%s'\n",
4390: IDENTIFIER_POINTER (METHOD_SEL_NAME (method_context)));
4391: return 1;
4392: }
4393: else
4394: return 0;
4395: }
4396:
4397: static int
4398: is_complex_decl (type)
4399: tree type;
4400: {
4401: return (TREE_CODE (type) == ARRAY_TYPE
4402: || TREE_CODE (type) == FUNCTION_TYPE
4403: || TREE_CODE (type) == POINTER_TYPE);
4404: }
4405:
4406:
4407: /* Code to convert a decl node into text for a declaration in C. */
4408:
4409: static char tmpbuf[256];
4410:
4411: static void
4412: adorn_decl (decl, str)
4413: tree decl;
4414: char *str;
4415: {
4416: enum tree_code code = TREE_CODE (decl);
4417:
4418: if (code == ARRAY_REF)
4419: {
4420: tree anIntCst = TREE_OPERAND (decl, 1);
4421:
4422: sprintf (str + strlen (str), "[%d]", TREE_INT_CST_LOW (anIntCst));
4423: }
4424: else if (code == ARRAY_TYPE)
4425: {
4426: tree anIntCst = TYPE_SIZE (decl);
4427: tree array_of = TREE_TYPE (decl);
4428:
4429: sprintf (str + strlen (str), "[%d]",
4430: TREE_INT_CST_LOW (anIntCst)/TREE_INT_CST_LOW (TYPE_SIZE (array_of)));
4431: }
4432: else if (code == CALL_EXPR)
4433: strcat (str, "()");
4434: else if (code == FUNCTION_TYPE)
4435: {
4436: tree chain = TYPE_ARG_TYPES (decl); /* a list of types */
4437: strcat (str, "(");
4438: while (chain && TREE_VALUE (chain) != void_type_node)
4439: {
4440: gen_declaration (TREE_VALUE (chain), str);
4441: chain = TREE_CHAIN (chain);
4442: if (chain && TREE_VALUE (chain) != void_type_node)
4443: strcat (str, ",");
4444: }
4445: strcat (str, ")");
4446: }
4447: else
4448: {
4449: strcpy (tmpbuf, "*"); strcat (tmpbuf, str);
4450: strcpy (str, tmpbuf);
4451: }
4452: }
4453:
4454: static char *
4455: gen_declarator (decl, buf, name)
4456: tree decl;
4457: char *buf;
4458: char *name;
4459: {
4460: if (decl)
4461: {
4462: enum tree_code code = TREE_CODE (decl);
4463: char *str;
4464: tree op;
4465: int wrap = 0;
4466:
4467: switch (code)
4468: {
4469: case ARRAY_REF: case INDIRECT_REF: case CALL_EXPR:
4470: {
4471: op = TREE_OPERAND (decl, 0);
4472:
4473: /* we have a pointer to a function or array...(*)(), (*)[] */
4474: if ((code == ARRAY_REF || code == CALL_EXPR) &&
4475: (op && TREE_CODE (op) == INDIRECT_REF))
4476: wrap = 1;
4477:
4478: str = gen_declarator (op, buf, name);
4479:
4480: if (wrap)
4481: {
4482: strcpy (tmpbuf, "("); strcat (tmpbuf, str); strcat (tmpbuf, ")");
4483: strcpy (str, tmpbuf);
4484: }
4485:
4486: adorn_decl (decl, str);
4487: break;
4488: }
4489: case ARRAY_TYPE: case FUNCTION_TYPE: case POINTER_TYPE:
4490: {
4491: str = strcpy (buf, name);
4492:
4493: /* this clause is done iteratively...rather than recursively */
4494: do
4495: {
4496: op = is_complex_decl (TREE_TYPE (decl))
4497: ? TREE_TYPE (decl)
4498: : NULLT;
4499:
4500: adorn_decl (decl, str);
4501:
4502: /* we have a pointer to a function or array...(*)(), (*)[] */
4503: if ((code == POINTER_TYPE) &&
4504: (op && (TREE_CODE (op) == FUNCTION_TYPE
4505: || TREE_CODE (op) == ARRAY_TYPE)))
4506: {
4507: strcpy (tmpbuf, "("); strcat (tmpbuf, str); strcat (tmpbuf, ")");
4508: strcpy (str, tmpbuf);
4509: }
4510:
4511: decl = is_complex_decl (TREE_TYPE (decl))
4512: ? TREE_TYPE (decl)
4513: : NULLT;
4514: }
4515: while (decl && (code = TREE_CODE (decl)));
4516:
4517: break;
4518: }
4519: case IDENTIFIER_NODE:
4520: /* will only happen if we are processing a "raw" expr-decl. */
4521: return strcpy (buf, IDENTIFIER_POINTER (decl));
4522: }
4523:
4524: return str;
4525: }
4526: else /* we have an abstract declarator or a _DECL node */
4527: {
4528: return strcpy (buf, name);
4529: }
4530: }
4531:
4532: static void
4533: gen_declspecs (declspecs, buf, raw)
4534: tree declspecs;
4535: char *buf;
4536: int raw;
4537: {
4538: if (raw)
4539: {
4540: tree chain;
4541:
4542: for (chain = declspecs; chain; chain = TREE_CHAIN (chain))
4543: {
4544: tree aspec = TREE_VALUE (chain);
4545:
4546: if (TREE_CODE (aspec) == IDENTIFIER_NODE)
4547: strcat (buf, IDENTIFIER_POINTER (aspec));
4548: else if (TREE_CODE (aspec) == RECORD_TYPE)
4549: {
4550: if (TYPE_NAME (aspec))
4551: {
4552: if (!TREE_STATIC_TEMPLATE (aspec))
4553: strcat (buf, "struct ");
4554: strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
4555: }
4556: else
4557: strcat (buf, "untagged struct");
4558: }
4559: else if (TREE_CODE (aspec) == UNION_TYPE)
4560: {
4561: if (TYPE_NAME (aspec))
4562: {
4563: if (!TREE_STATIC_TEMPLATE (aspec))
4564: strcat (buf, "union ");
4565: strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
4566: }
4567: else
4568: strcat (buf, "untagged union");
4569: }
4570: else if (TREE_CODE (aspec) == ENUMERAL_TYPE)
4571: {
4572: if (TYPE_NAME (aspec))
4573: {
4574: if (!TREE_STATIC_TEMPLATE (aspec))
4575: strcat (buf, "enum ");
4576: strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
4577: }
4578: else
4579: strcat (buf, "untagged enum");
4580: }
4581: strcat (buf, " ");
4582: }
4583: }
4584: else
4585: switch (TREE_CODE (declspecs))
4586: {
4587: /* type specifiers */
4588:
4589: case INTEGER_TYPE: /* signed integer types */
4590:
4591: if (declspecs == short_integer_type_node) /* 's' */
4592: strcat (buf, "short int ");
4593: else if (declspecs == integer_type_node) /* 'i' */
4594: strcat (buf, "int ");
4595: else if (declspecs == long_integer_type_node) /* 'l' */
4596: strcat (buf, "long int ");
4597: else if (declspecs == signed_char_type_node || /* 'c' */
4598: declspecs == char_type_node)
4599: strcat (buf, "char ");
4600:
4601: /* unsigned integer types */
4602:
4603: else if (declspecs == short_unsigned_type_node) /* 'S' */
4604: strcat (buf, "unsigned short ");
4605: else if (declspecs == unsigned_type_node) /* 'I' */
4606: strcat (buf, "unsigned int ");
4607: else if (declspecs == long_unsigned_type_node) /* 'L' */
4608: strcat (buf, "unsigned long ");
4609: else if (declspecs == unsigned_char_type_node) /* 'C' */
4610: strcat (buf, "unsigned char ");
4611: break;
4612:
4613: case REAL_TYPE: /* floating point types */
4614:
4615: if (declspecs == float_type_node) /* 'f' */
4616: strcat (buf, "float ");
4617: else if (declspecs == double_type_node) /* 'd' */
4618: strcat (buf, "double ");
4619: else if (declspecs == long_double_type_node) /* 'd' */
4620: strcat (buf, "long double ");
4621: break;
4622:
4623: case RECORD_TYPE:
4624: if (!TREE_STATIC_TEMPLATE (declspecs))
4625: strcat (buf, "struct ");
4626: if (TYPE_NAME (declspecs) &&
4627: (TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE))
4628: {
4629: strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
4630: strcat (buf, " ");
4631: }
4632: break;
4633: case UNION_TYPE:
4634: strcat (buf, "union ");
4635: if (TYPE_NAME (declspecs) &&
4636: (TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE))
4637: {
4638: strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
4639: strcat (buf, " ");
4640: }
4641: break;
4642: case ENUMERAL_TYPE:
4643: strcat (buf, "enum ");
4644: if (TYPE_NAME (declspecs) &&
4645: (TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE))
4646: {
4647: strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
4648: strcat (buf, " ");
4649: }
4650: break;
4651: case VOID_TYPE:
4652: strcat (buf, "void ");
4653: }
4654: }
4655:
4656: static char *
4657: gen_declaration (atype_or_adecl, buf)
4658: tree atype_or_adecl;
4659: char *buf;
4660: {
4661: char declbuf[256];
4662:
4663: if (TREE_CODE (atype_or_adecl) == TREE_LIST)
4664: {
4665: tree declspecs; /* "identifier_node", "record_type" */
4666: tree declarator; /* "array_ref", "indirect_ref", "call_expr"... */
4667:
4668: /* we have a "raw", abstract delclarator (typename) */
4669: declarator = TREE_VALUE (atype_or_adecl);
4670: declspecs = TREE_PURPOSE (atype_or_adecl);
4671:
4672: gen_declspecs (declspecs, buf, 1);
4673: strcat (buf, gen_declarator (declarator, declbuf, ""));
4674: }
4675: else
4676: {
4677: tree atype;
4678: tree declspecs; /* "integer_type", "real_type", "record_type"... */
4679: tree declarator; /* "array_type", "function_type", "pointer_type". */
4680:
4681: if (TREE_CODE (atype_or_adecl) == FIELD_DECL
4682: || TREE_CODE (atype_or_adecl) == PARM_DECL
4683: || TREE_CODE (atype_or_adecl) == FUNCTION_DECL)
4684: atype = TREE_TYPE (atype_or_adecl);
4685: else
4686: atype = atype_or_adecl; /* assume we have a *_type node */
4687:
4688: if (is_complex_decl (atype))
4689: {
4690: tree chain;
4691:
4692: /* get the declaration specifier...it is at the end of the list */
4693: declarator = chain = atype;
4694: do
4695: chain = TREE_TYPE (chain); /* not TREE_CHAIN (chain); */
4696: while (is_complex_decl (chain));
4697: declspecs = chain;
4698: }
4699: else
4700: {
4701: declspecs = atype;
4702: declarator = NULLT;
4703: }
4704:
4705: gen_declspecs (declspecs, buf, 0);
4706:
4707: if (TREE_CODE (atype_or_adecl) == FIELD_DECL
4708: || TREE_CODE (atype_or_adecl) == PARM_DECL
4709: || TREE_CODE (atype_or_adecl) == FUNCTION_DECL)
4710: {
4711: if (declarator)
4712: {
4713: strcat (buf, gen_declarator (declarator, declbuf,
4714: IDENTIFIER_POINTER (DECL_NAME (atype_or_adecl))));
4715: }
4716: else
4717: strcat (buf, IDENTIFIER_POINTER (DECL_NAME (atype_or_adecl)));
4718: }
4719: else
4720: {
4721: strcat (buf, gen_declarator (declarator, declbuf, ""));
4722: }
4723: }
4724: return buf;
4725: }
4726:
4727: #define RAW_TYPESPEC(meth) (TREE_VALUE (TREE_PURPOSE (TREE_TYPE (meth))))
4728:
4729: static char *
4730: gen_method_decl (method, buf)
4731: tree method;
4732: char *buf;
4733: {
4734: tree chain;
4735:
4736: if (RAW_TYPESPEC (method) != objc_object_reference)
4737: {
4738: strcpy (buf, "(");
4739: gen_declaration (TREE_TYPE (method), buf);
4740: strcat (buf, ")");
4741: }
4742:
4743: chain = METHOD_SEL_ARGS (method);
4744: if (chain)
4745: { /* we have a chain of keyword_decls */
4746: do
4747: {
4748: if (KEYWORD_KEY_NAME (chain))
4749: strcat (buf, IDENTIFIER_POINTER (KEYWORD_KEY_NAME (chain)));
4750:
4751: strcat (buf, ":");
4752: if (RAW_TYPESPEC (chain) != objc_object_reference)
4753: {
4754: strcat (buf, "(");
4755: gen_declaration (TREE_TYPE (chain), buf);
4756: strcat (buf, ")");
4757: }
4758: strcat (buf, IDENTIFIER_POINTER (KEYWORD_ARG_NAME (chain)));
4759: if (chain = TREE_CHAIN (chain))
4760: strcat (buf, " ");
4761: }
4762: while (chain);
4763:
4764: if (METHOD_ADD_ARGS (method) == (tree)1)
4765: strcat (buf, ", ...");
4766: else if (METHOD_ADD_ARGS (method))
4767: { /* we have a tree list node as generate by `get_parm_info ()' */
4768: chain = TREE_PURPOSE (METHOD_ADD_ARGS (method));
4769: /* know we have a chain of parm_decls */
4770: while (chain)
4771: {
4772: strcat (buf, ", ");
4773: gen_declaration (chain, buf);
4774: chain = TREE_CHAIN (chain);
4775: }
4776: }
4777: }
4778: else /* we have a unary selector */
4779: {
4780: strcat (buf, IDENTIFIER_POINTER (METHOD_SEL_NAME (method)));
4781: }
4782:
4783: return buf;
4784: }
4785:
4786: void
4787: gen_prototype (fp, decl)
4788: FILE *fp;
4789: tree decl;
4790: {
4791: /* we have a function definition - generate prototype */
4792: bzero (errbuf, BUFSIZE);
4793: gen_declaration (decl, errbuf);
4794: fprintf (fp, "%s;\n", errbuf);
4795: }
4796: /*
4797: * debug info...
4798: */
4799: static void
4800: dump_interface (fp, chain)
4801: FILE *fp;
4802: tree chain;
4803: {
4804: char *buf = (char *)xmalloc (256);
4805: char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain));
4806: tree ivar_decls = CLASS_RAW_IVARS (chain);
4807: tree nst_methods = CLASS_NST_METHODS (chain);
4808: tree cls_methods = CLASS_CLS_METHODS (chain);
4809:
4810: fprintf (fp, "\n@interface %s", my_name);
4811:
4812: if (CLASS_SUPER_NAME (chain))
4813: {
4814: char *super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain));
4815: fprintf (fp, " : %s\n", super_name);
4816: }
4817: else
4818: fprintf (fp, "\n");
4819:
4820: if (ivar_decls)
4821: {
4822: fprintf (fp, "{\n");
4823: do
4824: {
4825: bzero (buf, 256);
4826: fprintf (fp, "\t%s;\n", gen_declaration (ivar_decls, buf));
4827: ivar_decls = TREE_CHAIN (ivar_decls);
4828: }
4829: while (ivar_decls);
4830: fprintf (fp, "}\n");
4831: }
4832:
4833: while (nst_methods)
4834: {
4835: bzero (buf, 256);
4836: fprintf (fp, "- %s;\n", gen_method_decl (nst_methods, buf));
4837: nst_methods = TREE_CHAIN (nst_methods);
4838: }
4839:
4840: while (cls_methods)
4841: {
4842: bzero (buf, 256);
4843: fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods, buf));
4844: cls_methods = TREE_CHAIN (cls_methods);
4845: }
4846: fprintf (fp, "\n@end");
4847: }
4848:
4849: void
4850: init_objc ()
4851: {
4852: /* Add the special tree codes of Objective C to the tables. */
4853:
4854: tree_code_type
4855: = (char **) realloc (tree_code_type,
4856: sizeof (char *) * LAST_OBJC_TREE_CODE);
4857: tree_code_length
4858: = (int *) realloc (tree_code_length,
4859: sizeof (int) * LAST_OBJC_TREE_CODE);
4860: tree_code_name
4861: = (char **) realloc (tree_code_name,
4862: sizeof (char *) * LAST_OBJC_TREE_CODE);
4863: bcopy (objc_tree_code_type,
4864: tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE,
4865: (((int) LAST_OBJC_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE)
4866: * sizeof (char *)));
4867: bcopy (objc_tree_code_length,
4868: tree_code_length + (int) LAST_AND_UNUSED_TREE_CODE,
4869: (((int) LAST_OBJC_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE)
4870: * sizeof (int)));
4871: bcopy (objc_tree_code_name,
4872: tree_code_name + (int) LAST_AND_UNUSED_TREE_CODE,
4873: (((int) LAST_OBJC_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE)
4874: * sizeof (char *)));
4875:
4876: errbuf = (char *)xmalloc (BUFSIZE);
4877: utlbuf = (char *)xmalloc (BUFSIZE);
4878: hash_init ();
4879: synth_module_prologue ();
4880: }
4881:
4882: void
4883: finish_objc ()
4884: {
4885: struct imp_entry *impent;
4886: tree chain;
4887:
4888: generate_forward_declaration_to_string_table ();
4889:
4890: #ifdef OBJC_PROLOGUE
4891: OBJC_PROLOGUE;
4892: #endif
4893:
4894: if (implementation_context || sel_refdef_chain)
4895: generate_objc_symtab_decl ();
4896:
4897: for (impent = imp_list; impent; impent = impent->next)
4898: {
4899: implementation_context = impent->imp_context;
4900: implementation_template = impent->imp_template;
4901:
4902: _OBJC_CLASS_decl = impent->class_decl;
4903: _OBJC_METACLASS_decl = impent->meta_decl;
4904:
4905: if (TREE_CODE (implementation_context) == IMPLEMENTATION_TYPE)
4906: {
4907: /* all of the following reference the string pool... */
4908: generate_ivar_lists ();
4909: generate_dispatch_tables ();
4910: generate_shared_structures ();
4911: }
4912: else
4913: {
4914: generate_dispatch_tables ();
4915: generate_category (implementation_context);
4916: }
4917: }
4918:
4919: if (sel_ref_chain)
4920: build_selector_translation_table ();
4921:
4922: if (implementation_context || sel_refdef_chain)
4923: {
4924: /* Arrange for Objc data structures to be initialized at run time. */
4925:
4926: char *init_name = build_module_descriptor ();
4927: if (init_name)
4928: assemble_constructor (init_name);
4929: }
4930:
4931: /* dump the string table last */
4932:
4933: if (sel_refdef_chain)
4934: {
4935: build_message_selector_pool ();
4936: }
4937:
4938: /* dump the class references...this forces the appropriate classes
4939: to be linked into the executable image, preserving unix archive
4940: semantics...this can be removed when we move to a more dynamically
4941: linked environment
4942: */
4943: for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
4944: {
4945: tree decl;
4946:
4947: #if 0 /* Grossly unportable. */
4948: sprintf (utlbuf, ".reference .objc_class_name_%s",
4949: IDENTIFIER_POINTER (TREE_VALUE (chain)));
4950: assemble_asm (my_build_string (strlen (utlbuf) + 1, utlbuf));
4951: #else
4952: sprintf (utlbuf, ".objc_class_name_%s",
4953: IDENTIFIER_POINTER (TREE_VALUE (chain)));
4954: #endif
4955: /* Make a decl for this name, so we can use its address in a tree. */
4956: decl = build_decl (VAR_DECL, get_identifier (utlbuf), char_type_node);
4957: TREE_EXTERNAL (decl) = 1;
4958: TREE_PUBLIC (decl) = 1;
4959:
4960: pushdecl (decl);
4961: rest_of_decl_compilation (decl, 0, 0, 0);
4962:
4963: /* Make following constant read-only (why not)? */
4964: text_section ();
4965:
4966: /* Output a constant to reference this address. */
4967: output_constant (build1 (ADDR_EXPR, string_type_node, decl),
4968: int_size_in_bytes (string_type_node));
4969: }
4970:
4971: for (impent = imp_list; impent; impent = impent->next)
4972: {
4973: implementation_context = impent->imp_context;
4974: implementation_template = impent->imp_template;
4975:
4976: if (TREE_CODE (impent->imp_context) == IMPLEMENTATION_TYPE)
4977: {
4978: #if 0 /* Grossly unportable.
4979: People should know better than to assume
4980: such things about assembler syntax! */
4981: sprintf (utlbuf, ".objc_class_name_%s=0",
4982: IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)));
4983: assemble_asm (my_build_string (strlen (utlbuf) + 1, utlbuf));
4984: #endif
4985: sprintf (utlbuf, ".objc_class_name_%s",
4986: IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)));
4987: assemble_global (utlbuf);
4988: assemble_label (utlbuf);
4989: }
4990: else if (TREE_CODE (impent->imp_context) == CATEGORY_TYPE)
4991: {
4992: /* Do the same for categories. Even though no references to these
4993: symbols are generated automatically by the compiler, it gives
4994: you a handle to pull them into an archive by hand. */
4995: #if 0 /* Grossly unportable. */
4996: sprintf (utlbuf, ".objc_category_name_%s_%s=0",
4997: IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)),
4998: IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)));
4999: assemble_asm (my_build_string (strlen (utlbuf) + 1, utlbuf));
5000: #endif
5001: sprintf (utlbuf, ".objc_category_name_%s_%s",
5002: IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)),
5003: IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)));
5004: assemble_global (utlbuf);
5005: assemble_label (utlbuf);
5006: }
5007: }
5008: #if 0 /* If GAS has such a bug, let's fix it. */
5009: /*** this fixes a gross bug in the assembler...it `expects' #APP to have
5010: *** a matching #NO_APP, or it crashes (sometimes). app_disable () will
5011: *** insure this is the case. 5/19/89, s.naroff.
5012: ***/
5013: if (cls_ref_chain || imp_list)
5014: app_disable ();
5015: #endif
5016:
5017: if (flag_gen_declaration)
5018: {
5019: add_class (implementation_context);
5020: dump_interface (gen_declaration_file, implementation_context);
5021: }
5022: if (warn_selector)
5023: {
5024: int slot;
5025:
5026: /* Run through the selector hash tables and print a warning for any
5027: selector which has multiple methods. */
5028:
5029: for (slot = 0; slot < SIZEHASHTABLE; slot++)
5030: {
5031: hash hsh;
5032:
5033: for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
5034: {
5035: if (hsh->list)
5036: {
5037: tree meth = hsh->key;
5038: char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL)
5039: ? '-' : '+';
5040: attr loop;
5041:
5042: warning ("potential selector conflict for method `%s'",
5043: IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
5044: warn_with_method ("found", type, meth);
5045: for (loop = hsh->list; loop; loop = loop->next)
5046: warn_with_method ("found", type, loop->value);
5047: }
5048: }
5049: }
5050:
5051: for (slot = 0; slot < SIZEHASHTABLE; slot++)
5052: {
5053: hash hsh;
5054:
5055: for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
5056: {
5057: if (hsh->list)
5058: {
5059: tree meth = hsh->key;
5060: char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL)
5061: ? '-' : '+';
5062: attr loop;
5063:
5064: warning ("potential selector conflict for method `%s'",
5065: IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
5066: warn_with_method ("found", type, meth);
5067: for (loop = hsh->list; loop; loop = loop->next)
5068: warn_with_method ("found", type, loop->value);
5069: }
5070: }
5071: }
5072: }
5073: }
5074:
5075: #ifdef DEBUG
5076:
5077: static void
5078: objc_debug (fp)
5079: FILE *fp;
5080: {
5081: char *buf = (char *)xmalloc (256);
5082:
5083: { /* dump function prototypes */
5084: tree loop = _OBJC_MODULES_decl;
5085:
5086: fprintf (fp, "\n\nfunction prototypes:\n");
5087: while (loop)
5088: {
5089: if (TREE_CODE (loop) == FUNCTION_DECL && DECL_INITIAL (loop))
5090: {
5091: /* we have a function definition - generate prototype */
5092: bzero (errbuf, BUFSIZE);
5093: gen_declaration (loop, errbuf);
5094: fprintf (fp, "%s;\n", errbuf);
5095: }
5096: loop = TREE_CHAIN (loop);
5097: }
5098: }
5099: { /* dump global chains */
5100: tree loop;
5101: int i, index = 0, offset = 0;
5102: hash hashlist;
5103:
5104: for (i = 0; i < SIZEHASHTABLE; i++)
5105: {
5106: if (hashlist = nst_method_hash_list[i])
5107: {
5108: fprintf (fp, "\n\nnst_method_hash_list[%d]:\n", i);
5109: do
5110: {
5111: bzero (buf, 256);
5112: fprintf (fp, "-%s;\n", gen_method_decl (hashlist->key, buf));
5113: hashlist = hashlist->next;
5114: }
5115: while (hashlist);
5116: }
5117: }
5118: for (i = 0; i < SIZEHASHTABLE; i++)
5119: {
5120: if (hashlist = cls_method_hash_list[i])
5121: {
5122: fprintf (fp, "\n\ncls_method_hash_list[%d]:\n", i);
5123: do
5124: {
5125: bzero (buf, 256);
5126: fprintf (fp, "-%s;\n", gen_method_decl (hashlist->key, buf));
5127: hashlist = hashlist->next;
5128: }
5129: while (hashlist);
5130: }
5131: }
5132: fprintf (fp, "\nsel_refdef_chain:\n");
5133: for (loop = sel_refdef_chain; loop; loop = TREE_CHAIN (loop))
5134: {
5135: fprintf (fp, "(index: %4d offset: %4d) %s\n", index, offset,
5136: IDENTIFIER_POINTER (TREE_VALUE (loop)));
5137: index++;
5138: /* add one for the '\0' character */
5139: offset += IDENTIFIER_LENGTH (TREE_VALUE (loop)) + 1;
5140: }
5141: fprintf (fp, "\n (max_selector_index: %4d.\n", max_selector_index);
5142: }
5143: }
5144: #endif
5145:
5146: void
5147: print_lang_statistics ()
5148: {
5149: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.