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