|
|
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.