/* types.cc */ /* Type processing */ #include "types.h" #include "cmm_parser.hpp" #include "cmm_product.hpp" #include "str.h" #include "conv.h" #include "ioexception.h" #include "textio.h" #include "inf.h" #include "translate.h" #include "dict.h" #include "info.h" // function item_description #ifdef STORE_TO_REFLEX using namespace Reflex; #endif OPEN_NAMESPACE /* type options - global variables */ bool skip_functions = false; bool check_types = true; bool check_templates = true; bool check_all_types = true; bool check_inner_typenames = true; bool check_names = true; bool check_using = true; bool check_duplications = true; bool check_complete_lookup = true; bool check_template_arguments = true; bool notify_missing_include = true; bool enable_subst = true; bool expand_templates = true; bool store_to_dictionary = true; bool show_template_messages = false; bool show_detail_messages = false; /* global variables */ CttContextList context_list; CttContext * context = NULL; CttScope * top_scope = NULL; CttScope * target = NULL; CttScope * translation = NULL; int inside_class = 0; int inside_function = 0; int inside_template = 0; int inside_using = 0; TEnvInput * error_handler = NULL; /* functions */ CttItem * new_type (CmmDeclSpec * spec, CmmDeclarator * decl); void store_item (CttItem * item, bool remember = true); CttClass * produce_class (string name, string suffix, bool is_template, bool is_specialization, bool is_instance); void generate_template_instance (CttEval * eval); void assign_template_arguments (CttScope * inst); void expand_item (CttItem * item); void expand_scope (CttScope * scope); /* messages */ void Abort (string msg) { // only for functions // inside CmmParser class is another Abort method if (error_handler != NULL) error_handler->Abort (msg); else abort (msg); } void Error (string msg) { // only for functions // inside CmmParser class is another Error method if (error_handler != NULL) error_handler->Error (msg); else error (msg); } void Mistake (string msg) { // only for functions // inside CmmParser class is another Mistake method if (error_handler != NULL) error_handler->Mistake (msg); else mistake (msg); } void Flaw (string msg) { // only for functions // inside CmmParser class is another Flaw method if (error_handler != NULL) error_handler->Flaw (msg); else flaw (msg); } void Warning (string msg) { // only for functions // inside CmmParser class is another Warning method if (error_handler != NULL) error_handler->Warning (msg); else warning (msg); } void Problem (bool error_flag, string msg) { if (error_flag) Flaw (msg); else Mistake (msg); } #define check(c) \ if (!(c)) \ abort ("Check failed " #c ) /* initialization */ // const int global_items = 10000; // const int namespace_items = 1000; // const int class_items = 100; void init_global_scope () { /* context */ context_list.removeAll (); // !? not the best solution context_list.insertLast (new CttContext); context = context_list.first; /* global scope */ top_scope = new CttNamespace; // top_scope->dict.reinit (global_items); context->current_scope = top_scope; target = top_scope; translation = NULL; /* other global variables */ inside_class = 0; inside_function = 0; inside_template = 0; init_dict_variables (); } /********************************* TYPES **********************************/ CttItem * new_const_type (CttItem * type) { CttConstType * n = new CttConstType; n->elem = type; store_item (n); return n; } CttItem * new_volatile_type (CttItem * type) { CttVolatileType * n = new CttVolatileType; n->elem = type; store_item (n); return n; } void strange_type () { Flaw ("Strange simple type"); } CttSimpleType * new_simple_type (CmmDeclSpec * decl) { CttSimpleType * n = new CttSimpleType; if (decl->a_bool) n->sort = bool_type; else if (decl->a_char) n->sort = char_type; else if (decl->a_wchar) n->sort = wchar_type; else if (decl->a_float) n->sort = float_type; else if (decl->a_double) n->sort = double_type; else if (decl->a_void) n->sort = double_type; else n->sort = int_type; // short, long if (decl->a_short && decl->a_long) strange_type (); if (n->sort == int_type) { if (decl->a_short) n->sort = short_type; else if (decl->a_long >= 2) n->sort = long_long_type; else if (decl->a_long == 1) n->sort = long_type; // !? long long } else if (n->sort == double_type) { if (decl->a_short) strange_type (); if (decl->a_long) n->sort = long_double_type; } else { if (decl->a_short || decl->a_long) strange_type (); } // signed, unsigned if (decl->a_signed && decl->a_unsigned) strange_type (); if (n->sort == char_type) { if (decl->a_signed) n->sort = signed_char_type; if (decl->a_unsigned) n->sort = unsigned_char_type; } else if (n->sort == short_type) { if (decl->a_unsigned) n->sort = unsigned_short_type; } else if (n->sort == int_type) { if (decl->a_unsigned) n->sort = unsigned_int_type; } else if (n->sort == long_type) { if (decl->a_unsigned) n->sort = unsigned_long_type; } else if (n->sort == long_long_type) { if (decl->a_unsigned) n->sort = unsigned_long_long_type; } else { if (decl->a_signed || decl->a_unsigned) strange_type (); } store_item (n); return n; } void new_function_parameter (CttScope * scope, CmmParamItem * param) { CttSimple * n = new CttSimple; if (param->dots) n->name = "..."; // !? else if (param->type->decl->name == NULL) n->name = ""; // !? else n->name = compose_qualified_name (param->type->decl->name); if (param->type != NULL) // !? n->type = new_type (param->type->spec, param->type->decl); // if (param->init != NULL) // n->defualt_value = true; scope->insertLastItem (n); } CttFunction * new_function_type (CmmFunctionSpecifier * func, CttItem * result_type) { CttFunction * n = new CttFunction; n->is_type = true; // necessary n->function_parameters = new CttFunctionParams; // !? if (func->parameters != NULL) { CmmParamItem * param = func->parameters->first; while (param != NULL) { new_function_parameter (n->function_parameters, param); param = param->next; } } n->function_result = result_type; /* if (func->cv_const) type->const_function = true; if (func->cv_volatile) type->volatile_function = true; */ store_item (n); return n; } CttItem * new_decl_spec_type (CmmDeclSpec * decl) { CttItem * type = NULL; if (decl->basic_name != NULL) type = decl->basic_name->name_ref; // !? unknown name else if (decl->class_spec != NULL) type = decl->class_spec->name->name_ref; // !? anonymous class else if (decl->enum_spec != NULL) type = decl->enum_spec->name->name_ref; // !? anonymous enumeration type else if (decl->typename_spec != NULL) type = decl->typename_spec->name->name_ref; else type = new_simple_type (decl); if (decl->a_const) type = new_const_type (type); if (decl->a_volatile) type = new_volatile_type (type); return type; } bool is_function (CmmFunctionSpecifier * f) { assert (f != NULL); assert (f->parameters != NULL); bool result = true; CmmParamItem * p = f->parameters->first; while (p != NULL && result) { if (p->value != NULL) result = false; p = p->next; } return result; } CttItem * new_declarator_type (CmmDeclarator * decl, CttItem * type) { /* inner declarator */ if (decl->inner != NULL) type = new_declarator_type (decl->inner, type); /* pointer and references */ CmmPtrSpecifier * p = decl->ptr->first; while (p != NULL) { // !? if (p->pointer) { CttPointerType * n = new CttPointerType; n->elem = type; store_item (n); type = n; } else if (p->reference) { CttReferenceType * n = new CttReferenceType; n->is_type = true; store_item (n); type = n; } if (p->cv_const) type = new_const_type (type); if (p->cv_volatile) type = new_volatile_type (type); p = p->next; } /* arrays and functions */ CmmContSpecifier * c = decl->cont->last; while (c != NULL) { CmmArraySpecifier * a = c->conv_CmmArraySpecifier (); if (a != NULL) { CttArrayType * n = new CttArrayType; n->elem = type; // !? n->limit store_item (n); type = n; } else { CmmFunctionSpecifier * f = c->conv_CmmFunctionSpecifier (); if (is_function (f)) // !? type = new_function_type (f, type); } c = c->prev; // from last to first } return type; } CttItem * new_type (CmmDeclSpec * spec, CmmDeclarator * decl) { CttItem * type = new_decl_spec_type (spec); type = new_declarator_type (decl, type); return type; } /********************************* SCOPES *********************************/ CttScope * get_top_scope () { return top_scope; } CttContext * get_current_context () { return context; } #if 0 CttScope * get_current_target () { return target; } #endif /* ---------------------------------------------------------------------- */ void open_scope_and_context (CttScope * n) { // info ("open_scope_and_context " + get_full_item_name (n)); assert (context != NULL); // allocate new context if (context->next == NULL) context_list.insertLast (new CttContext); // set context context = context->next; assert (context != NULL); // set target check (n != NULL); context->current_scope = n; target = n; assert (context->current_name == NULL); } void close_scope_and_context () { assert (context != NULL); context->clear (); // erase all variables // set context context = context->prev; assert (context != NULL); // set target target = context->current_scope; check (target != NULL); // info ("close_scope_and_context"); } /* global context */ CttContext * open_global_context () { open_scope_and_context (top_scope); return context; } void close_global_context (CttContext * ctx) { context = ctx; // recovery from errors in source texxt close_scope_and_context (); } /* temporary context */ CttContext * open_temporary_context () { open_scope_and_context (target); return context; } void close_temporary_context (CttContext * ctx) { // recovery from errors in source text, important while (context != ctx) close_scope_and_context (); // and close temporary context close_scope_and_context (); } /********************************* LOOKUP *********************************/ #if 1 // global variable int lookup_level = 0; #endif CttItem * lookup (bool & virt, CttScope * scope, const string name, bool enable_above = false, bool enable_using = false, bool enable_ctor = false) { CttItem * result = NULL; #if 1 lookup_level ++; check (lookup_level <= 100); #endif if (! scope->ignore_scope) { // info ("lookup " + name + " in " + get_full_item_name (scope)); result = scope->dict.get (name); if (result != NULL && result->is_constructor && ! enable_ctor) result = NULL; if (result == NULL && scope->function_parameters != NULL) result = scope->function_parameters->dict.get (name); if (result == NULL && scope->template_parameters != NULL) { CttTemplateParams * p = scope->template_parameters; while (result == NULL && p != NULL) { result = p->dict.get (name); p = p->template_link; // outer template parameters } } if (result == NULL && scope->transient_method_scope != NULL) result = lookup (virt, scope->transient_method_scope, name, true); // including above scopes if (result == NULL && scope->transient_template_scope != NULL) { CttTemplateParams * p = scope->transient_template_scope; while (result == NULL && p != NULL) { result = p->dict.get (name); p = p->template_link; // outer template parameters } } if (result == NULL) { int cnt = 0; CttBase * b = scope->getFirstBase (); while (b != NULL && b->ref != NULL && ! virt) { CttItem * tmp = lookup (virt, b->ref, name); if (tmp != NULL && tmp != result) { result = tmp; if (b->virtual_base) virt = true; else cnt ++; } b = b->getNextBase (); } if (cnt > 1 && ! context->current_new_name) // !? Problem (check_complete_lookup, "Ambiguous identifier " + name + " in " + get_full_item_name (scope)); if (result == NULL && enable_using) { CttUsing * u = scope->getFirstUsing (); while (u != NULL) { CttItem * tmp = lookup (virt, u->ref, name); if (tmp != NULL && tmp != result) { result = tmp; cnt ++; } u = u->getNextUsing (); } if (cnt > 1 && ! context->current_new_name) // !? Problem (check_complete_lookup, "Ambiguous identifier " + name); } } } if (result == NULL && enable_above) { CttScope * a = scope->getAboveScope (); if (a != NULL) result = lookup (virt, a, name, enable_above, enable_using, enable_ctor); } #if 1 lookup_level --; #endif // if (result != NULL) // info ("succesful lookup " + name + " in " + get_full_item_name (scope)); return result; } CttItem * lookup_item (CttScope * scope, const string name, bool enable_using = false) { bool virt = false; CttItem * result = NULL; #if 1 lookup_level ++; check (lookup_level <= 100); #endif while (result == NULL && scope != NULL) { result = lookup (virt, scope, name, false, enable_using); scope = scope->getAboveScope (); } #if 1 lookup_level --; #endif return result; } CttItem * lookup_member (CttScope * scope, const string name) { bool virt = false; CttItem * result = NULL; result = lookup (virt, scope, name, false, true, true); return result; } /********************************* NAMES **********************************/ const string empty = "__EMPTY__"; // !? // global variable int empty_count = 0; // !? !! // forward declaration string retrieve_local_name (CmmName * name); string empty_name (CmmName * & name) // !? { assert (name == NULL); empty_count ++; name = new CmmName; // !? return empty + IntToStr (empty_count); } string simple_name (CmmName * & expr) // !? { check (expr != NULL); check (expr->first == NULL); return compose_qualified_name (expr); } /* ---------------------------------------------------------------------- */ CttItem * decode_name (CmmName * name) { assert (name != NULL); // info ("DECODE NAME " + compose_qualified_name (name)); CttItem * item = name->name_ref; // important while (item != NULL && item->alias_ref != NULL) item = item->alias_ref; // typedef or namespace alias return item; } /* ---------------------------------------------------------------------- */ CttScope * decode_scope (CttItem * item) { while (item != NULL && item->alias_ref != NULL) item = item->alias_ref; // typedef or namespace alias if (item == NULL) return NULL; else return item->to_scope (); } /* ---------------------------------------------------------------------- */ CttItem * resolve_base_name (CmmName * name) { // info ("resolve_base_name " + compose_base_name (name)); CttItem * item = NULL; string id = compose_base_name (name); if (name->a_global) item = lookup_item (top_scope, id); else item = lookup_item (target, id, true); // enable_using = true // info ("resolve_base_name " + compose_base_name (name) + " ... " + PtrToStr (item)); return item; } CttItem * resolve_cont_name (CttItem * base, CmmContName * cont) { // info ("resolve_cont_name " + compose_cont_name (cont)); string id = compose_cont_name (cont); CttScope * scope = NULL; if (base != NULL) scope = decode_scope (base); CttItem * item = NULL; if (scope != NULL) { item = lookup_member (scope, id); if (item == NULL) { bool in_template = scope->is_template || (scope->is_class && scope->is_template_instance) || scope->is_template_param; // !? if (inside_template) in_template = true; // !? bool enable_new_type = context->current_typename_prefix; if (! check_inner_typenames && ! scope->is_nested_param) enable_new_type = true; // cint - new identifier in nested parameter - probably function if (in_template && enable_new_type) { // create new class in template parameter open_scope_and_context (scope); CttClass * cls = produce_class (id, "", false, false, false); // !? cls->is_template_param = true; cls->is_nested_param = true; item = cls; close_scope_and_context (); // info ("CREATED " + get_full_item_name (cls)); } } } else { Problem (check_types, "Namespace or class required before scope resolution mark"); } bool in_template_param = (scope != NULL && scope->is_template_param); if (item == NULL && ! context->current_new_name && ! in_template_param) { if (! inside_using) { string txt = "Unknown field " + id; if (scope != NULL) txt = txt + " in " + get_full_item_name (scope); Problem (check_names, txt); } } return item; } /********************************* ITEMS **********************************/ /* items */ inline void remember_item (CttScope * scope, const string name, CttItem * item) { assert (scope != NULL); assert (item != NULL); assert (name != ""); // !? check name scope->dict.store (name, item); } inline void store_item (CttItem * item, bool remember) { assert (target != NULL); assert (item != NULL); target->insertLastItem (item); if (remember && item->name != "") remember_item (target, item->name, item); } /* ---------------------------------------------------------------------- */ void link_usage (CttItem * item, CmmBasic * name) { // add name into list of references assert (item != NULL); assert (name != NULL); if (item->first_usage == NULL) { assert (item->last_usage == NULL); item->first_usage = name; } else { assert (item->last_usage != NULL); item->last_usage->next_usage = name; item->last_usage = name; } item->last_usage = name; name->next_usage = NULL; } void link_decl (CttItem * item, CmmName * name, bool defn = false) { assert (item != NULL); assert (name != NULL); // !? !! check (name->name_ref == NULL); if (name->name_ref == NULL) name->name_ref = item; if (defn) { // !? check (item->defn_place == NULL); if (item->defn_place == NULL) item->defn_place = name; } else { // !? check (item->decl_place == NULL); if (item->decl_place == NULL) item->decl_place = name; } link_usage (item, name); // !? } /* ---------------------------------------------------------------------- */ void msg1 (CttItem * item, string name) { item_info ("Previous declaration: " + item->name, item); Error ("Identifier already declared as different object: " + name); } void msg2 (CttItem * item, string name) { if (check_duplications) { item_info ("Previous declaration: " + item->name, item); Problem (check_duplications, "Identifier already declared: " + name); } } /******************************* PARAMETERS *******************************/ /* template parameters */ inline CttTemplateParams * acquire_template_parameters () // get current template parameters ( from parser state variables ) { return context->current_template_params; } void combine_template_parameters (CttTemplateParams * & orig, CttTemplateParams * t) // mix old and new template parameters { if (orig == NULL) { // store new template parameters t->ignore_scope = true; // exclude from regular lookup orig = t; } else { // combine old and new template parameters CttItem * p = orig->getFirstItem (); CttItem * n = t->getFirstItem (); while (p != NULL && n != NULL) { if (! p->has_default_value () && n->has_default_value ()) { p->default_value = n->default_value; p->default_type_value = n->default_type_value; // !? some checks } p = p->getNextItem (); n = n->getNextItem (); } if (p != NULL || n != NULL) { Problem (check_template_arguments, "Different number of template parameters"); #if 0 p = orig->getFirstItem (); n = t->getFirstItem (); note ("First"); while (p != NULL) { note (" " + p->name); p = p->getNextItem (); } note ("Second"); while (n != NULL) { note (" " + n->name); n = n->getNextItem (); } #endif } } } void setup_template_parameters (CttScope * scope, CttTemplateParams * t) // store pointer to template parameters into CttScope { if (t != NULL) combine_template_parameters (scope->template_parameters, t); // probably do not follow template_link } void arrange_template_parameters (CttScope * scope, CttTemplateParams * t) // move template paramters into "templated" scope { #if 0 if (t != NULL) { t->removeItem (); scope->insertLastItem (t); // outer templates if (t->template_link != NULL) arrange_template_parameters (scope, t->template_link); } #endif } /* template arguments - used in template specializations */ inline CttEval * acquire_template_arguments () // get template argumnents ( from parser state variables ) { return context->current_eval; } void setup_another_template_arguments (CttScope * inst, CmmTemplateArgSect * args) { if (args != NULL) { // template specialization !? inst->is_template_specialization = true; inst->template_arguments = args; } } void setup_template_arguments (CttScope * inst, CttEval * eval) // store template arguments into CttScope { if (eval != NULL) { // info ("setup_template_arguments " + get_full_item_name (inst) + " ... " + get_full_item_name (eval)); #if 1 inst->template_eval = eval; // !? inst->is_template_instance = true; inst->template_reference = eval->template_reference; inst->template_arguments = eval->template_arguments; inst->signature = eval->signature; inst->translation_link = eval->translation_link; // !? // setup dictonary with parameters, open context and expand template assign_template_arguments (inst); // !? alias to template instance check (eval->alias_ref != NULL); eval->alias_ref->alias_ref = inst; // add final value to dictionary of instances eval->template_reference->template_instances.store (eval->signature, inst); #endif // store final value as alias to template expansion eval->alias_ref = inst; { // insert instance at the same level as original template CttScope * s = inst->template_reference; if (s != NULL) // !? { CttScope * c = s->getAboveScope (); // !? if (c != NULL) // !? !! { inst->removeItem (); c->insertLastItem (inst); // !? } } } { // add to list of instances CttScope * s = inst->template_reference; if (s != NULL) // !? { CttInst * r = new CttInst; r->ref = inst; s->insertLastInst (r); } } } } void arrange_template_arguments (CttScope * inst, CttEval * eval) { // nothing to move into 'inst' scope } /* functions parameters */ void setup_function_parameters (CttScope * scope, CttFunctionParams * p) // store pointer to function parameters into CttScope { if (p != NULL) { p->ignore_scope = true; // exclude from regular lookup check (scope->function_parameters == NULL); scope->function_parameters = p; } } void arrange_function_parameters (CttScope * scope, CttFunctionParams * p) // move function parameters into function scope { #if 0 if (p != NULL) { p->removeItem (); scope->insertLastItem (p); } #endif } /************************ ANALYZE DATA STRUCTURES *************************/ CttScope * retrieve_enclosing_scope (CmmName * name) // !? !! { assert (name != NULL); CttItem * item = NULL; CmmContName * cont = name->first; if (cont != NULL) { item = name->base_ref; while (cont != NULL && cont->next != NULL) { item = cont->cont_ref; cont = cont->next; } } CttScope * scope = NULL; if (item != NULL) { scope = item->to_scope (); if (scope == NULL) Flaw ("Namespace or class required before scope resolution mark"); } return scope; } string retrieve_local_name (CmmName * name) { assert (name != NULL); string id; CmmContName * cont = name->last; if (cont == NULL) id = compose_base_name (name); else id = compose_cont_name (cont); // !? return id; } CmmTemplateArgSect * retrieve_local_template_arguments (CmmName * name) { assert (name != NULL); CmmTemplateArgSect * result = NULL; CmmContName * cont = name->last; if (cont == NULL) result= name->template_args; else result = cont->template_args; return result; } /* ---------------------------------------------------------------------- */ CmmDeclarator * retrieve_inner_declarator (CmmDeclarator * decl) { assert (decl != NULL); while (decl->inner != NULL) decl = decl->inner; return decl; } CttFunctionParams * retrieve_inner_parameters (CmmDeclarator * decl) { CttFunctionParams * result = NULL; while (decl != NULL) { if (decl->cont != NULL) { CmmContSpecifier * item = decl->cont->first; bool stop = false; while (item != NULL && ! stop) { CmmFunctionSpecifier * func = item->conv_CmmFunctionSpecifier (); if (func != NULL && is_function (func)) // !? { result = func->param_ref; stop = true; // leave this level } item = item->next; } } decl = decl->inner; // continue to inner declarator } return result; } /* ---------------------------------------------------------------------- */ CttNamespace * find_namespace (CmmName * name) { CttItem * item = decode_name (name); CttNamespace * ns = NULL; if (item != NULL) ns = item->to_namespace (); if (ns == NULL) Problem (check_types, "Namespace expected: " + compose_qualified_name (name)); return ns; } CttScope * find_class (CmmName * name) { CttItem * item = decode_name (name); CttScope * scope = NULL; // !? !! check (item != NULL); if (item != NULL) scope = item->to_scope (); CttClass * cls = item->to_class (); if (cls == NULL) Problem (check_types, "Class expected: " + compose_qualified_name (name) + " " + translate_qualified_name (name)); return scope; } /* ---------------------------------------------------------------------- */ bool declarator_is_function (CmmDeclarator * decl) // !? !! { bool result = false; assert (decl != NULL); assert (decl->actual_decl != NULL); CmmDeclSpec * spec = decl->actual_decl->spec; assert (spec != NULL); CttFunctionParams * params = retrieve_inner_parameters (decl); result = (params != NULL); if (spec->a_typedef) result = false; // info ("declarator_is_function " + compose_declaration (spec, decl) + " = " + BoolToStr (result)); // function masked by typedefs !? return result; } /**************************** NAMESPACE SCOPE *****************************/ CttNamespace * produce_namespace (string name) // Create new namespace or use existing one { CttNamespace * result = NULL; assert (target != NULL); CttItem * item = target->dict.get (name); if (item == NULL) { result = new CttNamespace; result->name = name; store_item (result); } else { // is it namespace result = item->to_namespace (); if (result == NULL) msg1 (item, name); } return result; } /*************************** ENUMERATION SCOPE ****************************/ CttEnum * produce_enum_type (string name) // Create new enumeration type or use the existing one { CttEnum * result = NULL; assert (target != NULL); CttItem * item = target->dict.get (name); if (item == NULL) { result = new CttEnum; result->name = name; store_item (result); } else { result = item->to_enum (); if (result == NULL) msg1 (item, name); // !? } return result; } /* -------------------------- Enumeration Item -------------------------- */ CttSimple * produce_enum_item (string name) // Create new enumeration item { CttSimple * result = new CttSimple; result->name = name; // store into above context CttScope * scope = target->getAboveScope(); assert (scope != NULL); CttItem * item = scope->dict.get (name); if (item != NULL) msg1 (item, name); store_item (result); // store into scope of enumeration type remember_item (scope, name, result); // store into above scope return result; } /****************************** CLASS SCOPE *******************************/ CttClass * produce_class (string name, string suffix, bool is_template, bool is_specialization, bool is_instance) // Create new class or find existing class { CttClass * result = NULL; assert (context != NULL); assert (target != NULL); CttItem * item = target->dict.get (name+suffix); if (item == NULL) { // create new class result = new CttClass; result->name = name+suffix; // !? result->is_template = is_template; result->is_template_specialization = is_specialization; result->is_template_instance = is_instance; store_item (result); result->name = name; } else { // is it already in dictionary as class result = item->to_class (); if (result == NULL) { CttItem * alias = item->alias_ref; if (alias != NULL) { result = alias->to_class (); // typedef if (result != NULL) msg2 (result, name); // !? check boolean properties } } if (result == NULL) { // class expected msg1 (item, name); } } return result; } /***************************** FUNCTION SCOPE *****************************/ CttFunction * produce_function (string id, CttFunctionParams * params, bool is_template, bool ctor) // Create new function or use the existing one { CttFunction * result = NULL; string selection = compose_function_specifier (params->func_spec); // !? !! parameter names bool new_func = false; // create new function bool new_group = false; // create new group of functions CttFunctionGroup * group = NULL; CttFunction * orig_func = NULL; assert (context != NULL); assert (target != NULL); CttItem * item = target->dict.get (id); if (item == NULL) { new_func = true; } else { CttFunction * func = item->to_function (); if (func != NULL) { if (func->param_str == selection) { // !? always create new item without any parameters #if 1 new_group = true; orig_func = func; new_func = true; #else result = func; #endif // !? link to original declarations // !? other checks } else { new_group = true; orig_func = func; new_func = true; } } else { group = item->to_function_group (); if (group != NULL) { CttItem * temp = group->dict.get (selection); CttFunction * func = (temp == NULL) ? NULL : temp->to_function (); if (func != NULL) { #if 1 new_func = true; #else result = func; #endif // !? link to original declarations // !? other checks } else { new_func = true; } } else { // function or function group expected msg1 (item, id); new_func = true; } } } if (new_group) { // create group group = new CttFunctionGroup; group->name = id; group->is_template_group = is_template; group->is_constructor = ctor; store_item (group); if (orig_func != NULL) { // add original function to group orig_func->removeItem (); group->insertLastItem (orig_func); group->dict.store (orig_func->param_str, orig_func); } } if (new_func) { // create function item result = new CttFunction; result->name = id; result->is_template = is_template; result->is_constructor = ctor; result->param_str = selection; if (group == NULL) { store_item (result); } else { // add new function to group group->insertLastItem (result); group->dict.store (result->param_str, result); group->is_template_group = group->is_template_group || result->is_template; // !? check (group->is_constructor == ctor); } } assert (result != NULL); // info ("end of function_item"); return result; } /****************************** SIMPLE ITEM *******************************/ CttSimple * produce_simple_item (string id) // Create new variable, constant or typedef ( or use the existing one ) { // create simple item CttSimple * result = new CttSimple; result->name = id; // !? result->is_template = (t != NULL); // result->separate_decl = (scope != NULL); CttItem * item = target->dict.get (id); if (item == NULL) { store_item (result); } else { msg2 (item, id); // !? other checks } return result; } CttSimple * implement_simple_item (CmmDeclarator * declarator) { string id = declarator->short_name; CttScope * scope = retrieve_enclosing_scope (declarator->long_name); if (scope == NULL) { Flaw ("Unknown scope " + compose_qualified_name (declarator->long_name)); info ("? " + PtrToStr ( declarator->long_name->base_ref)); } // !? !! check (scope != NULL); if (scope != NULL) // !? !! open_scope_and_context (scope); CttItem * item = target->dict.get (id); if (item == NULL) Flaw ("Unknown identifier: " + id); else if (! item->is_simple) msg2 (item, id); // !? other checks // create simple item CttSimple * result = new CttSimple; result->name = id; store_item (result, false); // already in dictionary if (scope != NULL) // !? !! close_scope_and_context (); // !? !! link to original declaration return result; } /**************************** STORE NAMESPACE *****************************/ CttNamespace * introduce_namespace (string id) // Namespace declaration from source text or template expansion { CttNamespace * n = produce_namespace (id); if (inside_template == 0 && store_to_dictionary) describe_namespace (n); return n; } void create_namespace (CmmNamespaceDecl * decl) // Namespace declaration originated in source text { if (decl->name == NULL) { open_scope_and_context (get_top_scope ()); // !? !! anonymous namespace` } else { string id = simple_name (decl->name); // !? CttNamespace * n = introduce_namespace (id); // info ("open " + get_full_item_name (n)); open_scope_and_context (n); // do not store reference to declaration // namespace could be splitted to more sections // NO n->namespace_decl = decl; } } void finish_namespace () { // do not delete context->namespace_builder; // NO context->namespace_builder = NULL; // info ("close " + get_full_item_name (target)); close_scope_and_context (); } /* following methods are called from ckit.g */ /* namespace declaration */ void CmmParser::open_namespace (CmmNamespaceDecl * decl) { create_namespace (decl); } void CmmParser::close_namespace (CmmNamespaceDecl * decl) { finish_namespace (); } /* namespace alias */ void CmmParser::add_namespace_alias (CmmNamespaceDecl * decl) { /* namespace = */ string name = compose_qualified_name (decl->name); // !? CttNamespace * value = find_namespace (decl->value); // may be NULL // info ("ALIAS " + name); // !? check local name CttNamespace * item = new CttNamespace; item->name = name; item->alias_ref = value; store_item (item); #ifdef STORE_TO_REFLEX // !? #endif } /* using namespace */ void CmmParser::open_using (CmmUsingDecl * decl) // !? { inside_using ++; } void CmmParser::close_using (CmmUsingDecl * decl) // !? { if (decl->a_namespace) { /* using namespace */ CttUsing * u = new CttUsing; u->ref = find_namespace (decl->name); // may be NULL target->insertLastUsing (u); // info ("USING NAMESPACE" + get_qualified_name (decl->name)); } else { /* using */ CttItem * value = decode_name (decl->name); if (value == NULL) { Problem (check_using, "Unknown object " + compose_qualified_name (decl->name)); } else { string id = retrieve_local_name (decl->name); remember_item (target, id, value); // !? check local name } // info ("USING " + get_qualified_name (decl->name) + " = " + get_full_item_name(value)); } #ifdef STORE_TO_REFLEX // !? #endif inside_using --; } /************************* STORE ENUMERATION TYPE *************************/ CttEnum * introduce_enum_type (CmmEnumDecl * decl) // Enumeration type from source text or template expansion { string id = ""; if (decl->name == NULL) id = empty_name (decl->name); else id = simple_name (decl->name); CttEnum * n = produce_enum_type (id); n->enum_decl = decl; if (inside_template == 0 && store_to_dictionary) describe_enum (n); return n; } void create_enum_type (CmmEnumDecl * decl) { CttEnum * n = introduce_enum_type (decl); link_decl (n, decl->name); open_scope_and_context (n); } void finish_enum_type () { close_scope_and_context (); } /* following methods are called from ckit.g */ /* enum item */ CttSimple * introduce_enum_item (CmmEnumItem * decl) { string id = simple_name (decl->name); // !? CttSimple * item = produce_enum_item (id); item->enum_decl = decl; // !? !! enum value if (inside_template == 0 && store_to_dictionary) describe_enum_item (item); return item; } void create_enum_item (CmmEnumItem * decl) { CttSimple * item = introduce_enum_item (decl); link_decl (item, decl->name); } /* enumeration type declaration */ void CmmParser::open_enum_type (CmmEnumDecl * decl) { create_enum_type (decl); } void CmmParser::close_enum_type (CmmEnumDecl * decl) { finish_enum_type (); } /* forward enumeration type declaration */ void CmmParser::add_enum_forw (CmmEnumDecl * decl) { // forward declaraton without items, only create scope create_enum_type (decl); finish_enum_type (); } /* enumeration item */ void CmmParser::add_enum_item (CmmEnumItem * decl) { create_enum_item (decl); } /****************************** STORE CLASS *******************************/ CttClass * introduce_class_type (CmmClassDecl * decl, CttTemplateParams * template_params, CttEval * template_args, bool forw = false) // New class from source text or from template expansion { CttScope * scope = NULL; string id = ""; CmmTemplateArgSect * ext = NULL; if (decl->name == NULL) { id = empty_name (decl->name); } else { scope = retrieve_enclosing_scope (decl->name); id = retrieve_local_name (decl->name); if (template_args == NULL) ext = retrieve_local_template_arguments (decl->name); } if (scope != NULL) open_scope_and_context (scope); if (ext != NULL) if (show_template_messages) info ("SPECIALIZATION " + id + translate_template_arg_list (ext)); // !? string suffix = ""; if (ext != NULL) suffix = translate_template_arg_list (ext); else if (template_args != NULL) suffix = translate_template_arg_list (template_args->template_arguments); // create new class or use existing one CttClass * n = produce_class (id, suffix, template_params != NULL, ext != NULL, template_args != NULL); if (! forw || n->class_decl == NULL) n->class_decl = decl; // store Cmm declaration // template setup_template_parameters (n, template_params); setup_template_arguments (n, template_args); setup_another_template_arguments (n, ext); // store to dictionary if (inside_template == 0 && store_to_dictionary) describe_class (n); if (scope != NULL) close_scope_and_context (); return n; } void create_class_type (CmmClassDecl * decl, bool forw = false) // New class found in the source text { // template CttTemplateParams * t = acquire_template_parameters (); CttEval * e = acquire_template_arguments (); CttClass * n = introduce_class_type (decl, t, e, forw); context->current_access = (decl->style == ClassStyle) ? PrivateAccess : PublicAccess; link_decl (n, decl->name, ! forw); // move parameters into class scope arrange_template_arguments (n, e); // !? arrange_template_parameters (n, t); open_scope_and_context (n); } void finish_class_type () { // do not delete context->class_builder, builder may be re-used again close_scope_and_context (); } /* friend class */ void create_friend_class (CmmClassDecl * decl) { /* nothing */ } /* following methods are called from ckit.g */ /* class declaration */ void CmmParser::open_class (CmmClassDecl * decl) { assert (context->current_specifiers != NULL); bool friend_decl = context->current_specifiers->a_friend; assert (context->current_friend == false); context->current_friend = friend_decl; if (friend_decl) { create_friend_class (decl); } else { create_class_type (decl); inside_class ++; } } void CmmParser::close_class (CmmClassDecl * decl) { bool friend_decl = context->current_friend; if (! friend_decl) { finish_class_type (); inside_class --; } context->current_friend = false; } /* forward class declaration */ void CmmParser::add_class_forw (CmmClassDecl * decl) { assert (context->current_specifiers != NULL); bool friend_decl = context->current_specifiers->a_friend; if (friend_decl) { create_friend_class (decl); } else { create_class_type (decl, true); finish_class_type (); } } /* base classes */ void create_class_base (CmmBaseItem * decl) { CttBase * u = new CttBase; u->virtual_base = decl->a_virtual; u->base_access = decl->access; u->base_decl = decl; u->ref = find_class (decl->from); // may be NULL target->insertLastBase (u); // do not store base classes into dictionary if (inside_template == 0 && store_to_dictionary) describe_base (u); } void CmmParser::add_base (CmmBaseItem * decl) { create_class_base (decl); } /* member item visibility */ void CmmParser::add_visibility (CmmMemberVisibility * node) { context->current_access = node->access; } /***************************** STORE FUNCTION *****************************/ CttFunction * introduce_function_item (CmmDeclarator * declarator, CttTemplateParams * template_params, CttEval * template_args) // Function declaration from source text or template expansion { // create CttFunction object // used inside create_function_item (new declator encountered) // and inside expand_function (template expansion) assert (declarator != NULL); assert (declarator->actual_decl != NULL); string id = declarator->short_name; CmmTemplateArgSect * ext = NULL; if (template_args == NULL) ext = retrieve_local_template_arguments (declarator->long_name); // constructors and destructors bool ctor = false; bool dtor = false; CmmCtorDecl * ctor_decl = declarator->actual_decl->conv_CmmCtorDecl (); if (ctor_decl != NULL) { ctor = true; if (ctor_decl->destructor) ctor = false; CmmName * n = declarator->long_name; if (n != NULL) { CmmContName * c = n->last; if (c != NULL && c->a_destructor) ctor = false; } if (! ctor) { dtor = true; id = "~" + id; } #if 0 if (ctor) info ("CONSTRUCTOR " + compose_qualified_name (declarator->long_name)); if (dtor) info ("DESTRUCTOR " + compose_qualified_name (declarator->long_name)); #endif } // special functions bool spec = false; { CmmName * n = declarator->long_name; if (n != NULL && n->spec_func != NULL) spec = true; } // create Ctt object CttFunction * item = produce_function (id, declarator->function_param_ref, template_params != NULL, ctor); item->is_destructor = dtor; item->is_special_func = spec; item->access = declarator->access_val; item->separate_decl = declarator->separate_decl; item->func_decl = declarator->actual_decl; item->declarator = declarator; // and Ctt declarator within this declaration item->function_result = new_type (declarator->actual_decl->spec, declarator); // template setup_template_parameters (item, template_params); setup_template_arguments (item, template_args); setup_another_template_arguments (item, ext); // function parameters setup_function_parameters (item, declarator->function_param_ref); if (inside_function == 0) if (inside_template == 0 && store_to_dictionary) describe_function (item); // store to dictionary return item; } CttFunction * create_function_item (CmmDeclarator * declarator) { // info ("create_function_item in " + get_full_item_name (target)); // template CttTemplateParams * t = acquire_template_parameters (); CttEval * e = acquire_template_arguments (); // get parameters from inner declarator CttFunctionParams * params = retrieve_inner_parameters (declarator); declarator->function_param_ref = params; // create Ctt object CttFunction * item = introduce_function_item (declarator, t, e); // template arrange_template_parameters (item, t); // !? arrange_template_arguments (item, e); // !? // function parameters arrange_function_parameters (item, params); // !? link_decl (item, declarator->long_name); return item; } /*********************** STORE SIMPLE DECLARATION *************************/ /* constant, variable or type definition */ CmmName * retrieve_name (CmmDeclSpec * spec, CmmDeclarator * decl) { CmmName * result = NULL; if (! spec->a_const && ! spec->a_volatile /* && decl->ptr == NULL && decl->inner == NULL && decl->cont == NULL */ ) // !? !! { if (spec->basic_name != NULL) result = spec->basic_name; else if (spec->typename_spec != NULL) result = spec->typename_spec->name; } return result; } CttSimple * introduce_simple_item (CmmDeclarator * declarator) // Variable, constant or typedef declaration from source text or template expansion { assert (declarator != NULL); CttSimple * item = NULL; if (declarator->long_name->first != NULL) { // !? A::B item = implement_simple_item (declarator); item->separate_decl = true; // !? } else { item = produce_simple_item (declarator->short_name); item->access = declarator->access_val; item->separate_decl = declarator->separate_decl; item->decl_spec = declarator->actual_decl->spec; item->declarator = declarator; item->type = new_type (declarator->actual_decl->spec, declarator); if (item->decl_spec->a_typedef) { item->is_type = true; // info ("typedef " + item->name); // important for typedef(s) CmmName * n = retrieve_name (item->decl_spec, item->declarator); if (n != NULL) { CttItem * i = decode_name (n); // important for typedef(s) // while (i != NULL && i->alias_ref != NULL) // i = i->alias_ref; item->alias_ref = i; } } if (inside_function == 0) if (inside_template == 0 && store_to_dictionary) describe_simple (item); } return item; } CttSimple * create_simple_item (CmmDeclarator * declarator) { // template CttTemplateParams * t = acquire_template_parameters (); // !? !! // NOT IMPLEMENTED check (t == NULL); // !? CttEval * e = acquire_template_arguments (); check (e == NULL); CttSimple * item = introduce_simple_item (declarator); link_decl (item, declarator->long_name); return item; } /*************************** STORE DECLARATION ****************************/ /* function or simple declaration */ void create_declaration (CmmDeclarator * declarator) { // access assert (declarator != NULL); declarator->access_val = context->current_access; // enclosing declaration assert (context->current_decl != NULL); declarator->actual_decl = context->current_decl; // retrieve name from inner declarator CmmDeclarator * d = retrieve_inner_declarator (declarator); assert (d != NULL && d->name != NULL); // scope CttScope * scope = retrieve_enclosing_scope (d->name); string id = retrieve_local_name (d->name); // store name declarator->short_name = id; // !? declarator->long_name = d->name; // !? declarator->separate_decl = (scope != NULL); CttContext * orig_context = context; bool skip = skip_functions && (scope != NULL); if (! skip) { if (scope != NULL) open_scope_and_context (scope); if (declarator_is_function (declarator)) // !? // function masked by typedefs !? { CttFunction * func = create_function_item (declarator); // !? NO func->method_scope = scope; // !? enclosing class scope // !? !! namespace // DO NOT USE func_decl->getFirst (), NOT VALID NOW check (orig_context->current_function == NULL); orig_context->current_function = func; } else { create_simple_item (declarator); } // scope if (scope != NULL) close_scope_and_context (); } } /* friend declaration */ void create_friend_declaration (CmmDeclarator * declarator) { /* nothing */ } /* following methods are called from ckit.g */ /* declaration specifiers */ void CmmParser::open_decl_specifiers (CmmDeclSpec * spec) { // info ("open_decl_specifiers"); check (context->current_specifiers == NULL); context->current_specifiers = spec; } void CmmParser::close_decl_specifiers (CmmDeclSpec * spec) { context->current_specifiers = NULL; // info ("close_decl_specifiers"); } /* declaration */ void CmmParser::open_simple_declaration (CmmSimpleDecl * decl) { // info ("open_simple_declaration"); check (context->current_decl == NULL); context->current_decl = decl; } void CmmParser::close_simple_declaration (CmmSimpleDecl * decl) { // if (context->current_function != NULL) // info ("end of current_function"); context->current_function = NULL; context->current_decl = NULL; // info ("close_simple_declaration"); } void CmmParser::open_constructor_declaration (CmmCtorDecl * decl) { // info ("open_constructor_declaration"); open_simple_declaration (decl); } void CmmParser::close_constructor_declaration (CmmCtorDecl * decl) { close_simple_declaration (decl); // info ("close_constructor_declaration"); } /* declarators */ void CmmParser::open_declarator (CmmDeclarator * declarator) { declarator->save = context->current_declarator; // required by inner declarators context->current_declarator = declarator; } void CmmParser::close_declarator (CmmDeclarator * declarator) { context->current_declarator = declarator->save; } void CmmParser::add_declarator (CmmDeclarator * declarator) { if (context->current_decl->spec->a_friend) create_friend_declaration (declarator); else create_declaration (declarator); } /*********************** STORE FUNCTION PARAMETERS ************************/ // called from ckit.g void CmmParser::open_parameters (CmmFunctionSpecifier * func) { // function name with optional scope assert (context->current_declarator != NULL); CmmName * name = context->current_declarator->name; // function parameteres CttFunctionParams * p = new CttFunctionParams; p->func_spec = func; // open context for paramaters store_item (p, false); open_scope_and_context (p); check (target->transient_method_scope == NULL); if (name != NULL) { // outer (class) scope CttScope * scope = retrieve_enclosing_scope (name); target->transient_method_scope = scope; // temporary value, used during parameter declaration } // store to CttFunction assert (func->param_ref == NULL); func->param_ref = p; } void CmmParser::close_parameters (CmmFunctionSpecifier * func) { // forget scopes used only for parameter types target->transient_method_scope = NULL; assert (func->param_ref == target); // CttFunctionParams * p = context->to_function_params (); close_scope_and_context (); } void CmmParser::add_parameter (CmmParamItem * parameter) { if (! parameter->dots) // !? { string id = ""; CmmName * name = NULL; if (parameter->type != NULL && parameter->type->decl != NULL) { CmmDeclarator * d = retrieve_inner_declarator (parameter->type->decl); name = d->name; if (name != NULL) id = retrieve_local_name (name); // !? } CttSimple * item = new CttSimple; item->name = id; if (parameter->type != NULL) // !? { item->decl_spec = parameter->type->spec; item->declarator = parameter->type->decl; } store_item (item); // !? !! item->declarator->actual_spec = item->decl_spec; if (name != NULL) link_decl (item, name); #ifdef STORE_TO_REFLEX // !? #endif } } /*********************** STORE FUNCTION DEFINITION ************************/ // called from ckit.g /* function body */ void CmmParser::open_function (CmmFunctionBody * decl) { inside_function ++; if (! skip_functions) { // retrieve current function declaration CttFunction * f = context->current_function; check (f != NULL); // !? // open scope for function body open_scope_and_context (f); } } void CmmParser::close_function (CmmFunctionBody * decl) { inside_function --; if (! skip_functions) close_scope_and_context (); } /* block statement */ void CmmParser::open_block () { CttBlock * b = new CttBlock; store_item (b, false); open_scope_and_context (b); } void CmmParser::close_block () { close_scope_and_context (); } void CmmParser::read_block () { if (skip_functions) { int level = 0; while (level != 0 || ! symbol (RBRACE)) { if (symbol (LBRACE)) level ++; if (symbol (RBRACE)) level --; next (); } } } /* initialization */ void CmmParser::read_param_init () { #if 1 if (skip_functions && symbol (ASSIGN)) { next (); // skip '=' int level = 0; while (level != 0 || ! symbol (COMMA) && ! symbol (RPAREN)) { if (symbol (LPAREN)) level ++; if (symbol (RPAREN)) level --; next (); } } #endif } void CmmParser::read_enum_init () { #if 1 if (skip_functions && symbol (ASSIGN)) { next (); // skip '=' int level = 0; while (level != 0 || ! symbol (COMMA) && ! symbol (RBRACE)) { if (symbol (LPAREN)) level ++; if (symbol (RPAREN)) level --; next (); } } #endif } void CmmParser::read_initializer () { #if 1 if (skip_functions && symbol (ASSIGN)) { next (); // skip '=' int level = 0; while (level != 0 || ! symbol (COMMA) && ! symbol (SEMICOLON) && ! symbol (RBRACE)) { if (symbol (LPAREN) || symbol (LBRACE)) level ++; if (symbol (RPAREN) || symbol (RBRACE)) level --; next (); } } #endif } void CmmParser::read_member_initializer () { #if 1 if (skip_functions) { int level = 0; while (level != 0 || ! symbol (RPAREN)) { if (symbol (LPAREN)) level ++; if (symbol (RPAREN)) level --; next (); } } #endif } void CmmParser::read_array_size () { #if 1 if (skip_functions) { int level = 0; while (level != 0 || ! symbol (RBRACKET)) { if (symbol (LBRACKET)) level ++; if (symbol (RBRACKET)) level --; next (); } } #endif } /* conversion names */ void CmmParser::open_conversion () { // conversion may be used in names => open new context CttConv * c = new CttConv; // !? store_item (c); open_scope_and_context (c); } void CmmParser::close_conversion () { close_scope_and_context (); } /*********************** STORE TEMPLATE PARAMETERS ************************/ // called from ckit.g /* template declaration */ void CmmParser::open_template (CmmTemplateDecl * decl) // "template" keyword encountered { // create object for template parameters CttTemplateParams * t = new CttTemplateParams; t->template_decl = decl; // link to Cmm object store_item (t, false); // insert into current scope // open scope for template parameters open_scope_and_context (t); // following template parameters will be stored into new scope inside_template ++; } void CmmParser::add_template (CmmTemplateDecl * decl) // closing ">" encountered { CttTemplateParams * t = target->to_template_params (); assert (t != NULL); // remove template parameters from scope stack // folowing declarations should be stored into enclosing scope close_scope_and_context (); check (t->template_link == NULL); t->template_link = context->current_template_params; // link to outer template parameters context->current_template_params = t; // scope with template parameters check (target->transient_template_scope == t->template_link); // !? multiple use of target->template_scope target->transient_template_scope = t; } void CmmParser::close_template (CmmTemplateDecl * decl) // end of template declaration (incluiding inner declaration) { target->transient_template_scope = NULL; context->current_template_params = NULL; inside_template --; // NO close_scope_and_context, already done by add_template } /* template type parameters */ void CmmParser::add_template_type_param (CmmTemplateTypeParam * decl) { CttClass * item = new CttClass; if (decl->name != NULL) // possible anonymous parameter item->name = compose_qualified_name (decl->name); // !? item->is_template_param = true; item->is_type = true; // info ("... add " + item->name + " to " + get_full_item_name (target)); store_item (item); if (decl->name != NULL) link_decl (item, decl->name); if (decl->init_type != NULL) { item->default_type_value = decl->init_type; // info (get_full_item_name (item) + " with default value"); } else { // info (get_full_item_name (item) + " without default value"); } // !? more info } /* template value parameters */ void CmmParser::add_template_value_param (CmmTemplateValueParam * decl) { CttSimple * item = new CttSimple; CmmDeclarator * d = retrieve_inner_declarator (decl->type->decl); CmmName * n = d->name; if (n != NULL) // !? item->name = compose_qualified_name (n); item->is_type = false; item->is_template_param = true; if (decl->init_value != NULL) item->default_value = decl->init_value; store_item (item); if (n != NULL) link_decl (item, n); // !? more info } /*********************** STORE TEMPLATE ARGUMENTS *************************/ /* template arguments */ void CmmParser::open_template_arguments (CmmTemplateArgSect * args) // opening "<" encountered { // get current name CmmName * active_name = context->current_name; check (active_name != NULL); // get pointer to Ctt template object CttScope * temp = NULL; if (active_name->name_ref != NULL) // !? !! temp = active_name->name_ref->to_scope (); if (temp == NULL) Problem (check_templates, "Unknown template name"); // create CttEval object which represents template invocation // this object is also used for template expansion inside another templates CttEval * e = new CttEval; if (temp != NULL) e->name = temp->name; // not necessary e->template_reference = temp; // store pointer (NULL if template is not known) e->template_arguments = args; // store template arguments (now empty) e->alias_ref = temp; // required for type identification // open auxiliary scope for template evaluation store_item (e, false); open_scope_and_context (e); } void CmmParser::close_template_arguments (CmmTemplateArgSect * args) // closing ">" encountered { // get pointer to object which represents template invocation CttEval * eval = target->to_eval (); assert (eval != NULL); // close auxiliary scope close_scope_and_context (); // if context->current_new_name is true, // do not expand template // ( template arguments are returned throw acquire_template_arguments function ) // if (context->current_new_name) // context->current_eval = eval; // !? !! // !? check global_declaring_name and global_type_name if (! context->current_new_name) { // get current name (from outer context) CmmName * active_name = context->current_name; check (active_name != NULL); // store pointer to "evaluation" object into current identifier active_name->name_ref = eval; // eval->template_reference is NULL when template is not declared // ( and check_types == false or check_templates == false ) // see open_template_arguments // template expansion if (inside_template == 0 && expand_templates && eval->template_reference != NULL) { // if (eval->template_reference == NULL) // Error ("Bad template: " + get_full_item_name (eval)); if (! eval->template_reference->is_template) Error ("Not a template: " + get_full_item_name (eval)); // expand template ( if not already expanded ) generate_template_instance (eval); } // alias to template evaluation is stored // template is not necessary expanded now } } /*************************** TEMPLATE INSTANCES ***************************/ void generate_template_instance (CttEval * eval) { // called during parsing of top level template // or from expand_item during inner template expansion assert (eval != NULL); CttScope * temp = eval->template_reference; CmmTemplateArgSect * args = eval->template_arguments; assert (temp != NULL); // template class or function assert (temp->is_template); assert (args != NULL); // create signature from template arguments stored in CttEval string signature = translate_template_arg_list (args); // !? !! missing default arguments eval->signature = signature; // check if instance is not already generated CttScope * inst = temp->template_instances.get (signature); // info ("try " + temp->name + " " + signature + " " + NumToHex (temp)); if (inst != NULL) { eval->alias_ref = inst; // alias to template expansion } else { // info ("EXPAND " + temp->name + " " + signature); #if 1 // create auxiliary object // !? CttExpand * expand = new CttExpand; expand->name = temp->name; // not necessary, only for information output expand->template_reference = temp; expand->template_arguments = args; expand->signature = signature; expand->is_type = temp->is_type; // required for type identification // add temporary value to dictionary of instances (before another processing) temp->template_instances.store (signature, expand); // store temporary value as alias to template expansion eval->alias_ref = expand; store_item (expand, false); // !? open_translation (expand); open_scope_and_context (expand); #else open_translation (eval); open_scope_and_context (eval); #endif context->current_eval = eval; // Template arguments are store in current context // they are used by expand_class, introduce_class_type // (expand_function and introduce_function_item) // and finally by setup_template_arguments (). // Function setup_template_arguments // inserts new (expanded) declaration into correct place. expand_item (temp); close_scope_and_context (); close_translation (); if (show_template_messages) info ("END OF EXPAND " + temp->name + signature); } } /* ---------------------------------------------------------------------- */ void assign_template_arguments (CttScope * inst) { CttItem * temp = inst->template_reference; CmmTemplateArgSect * args = inst->template_arguments; // info ("assign_template_arguments: " + get_full_item_name (temp)); CttItem * param = NULL; { CttScope * t = temp->to_scope (); // !? if (t != NULL && t->template_parameters != NULL) param = t->template_parameters->getFirstItem (); } // skip CttEval and CttExpand in template parameter scope -- should be changed while (param != NULL && (param->is_eval || param->is_expand)) param = param->getNextItem (); #if 0 { CttItem * p = param; while (p != NULL) { if (! p->is_eval && ! p->is_expand) info ("... template parameter " + p->name); else info ("... eval/expand in template parameters " + p->name); p = p->getNextItem (); } } #endif CmmTemplateArg * arg = args->first; while (arg != NULL) { // info ("template parameter (1) " + param->name); if (param == NULL) { Problem (check_template_arguments, "Too many template arguments"); } else { inst->template_arg_dict.store (param, arg); // info ("template parameter " + param->name + " = " + translate_template_arg (arg)); param = param->getNextItem (); while (param != NULL && (param->is_eval || param->is_expand)) param = param->getNextItem (); } arg = arg->next; } while (param != NULL && (param->is_eval || param->is_expand)) param = param->getNextItem (); while (param != NULL && param->has_default_value ()) { // info ("template parameter (2) " + param->name); if (param->default_type_value != NULL) { CmmTemplateTypeArg * a = new CmmTemplateTypeArg; a->type = param->default_type_value; arg = a; } else { CmmTemplateValueArg * a = new CmmTemplateValueArg; a->value = param->default_value; arg = a; } inst->template_arg_dict.store (param, arg); // info ("default template parameter " + param->name + " = " + translate_template_arg (arg)); param = param->getNextItem (); while (param != NULL && (param->is_eval || param->is_expand)) param = param->getNextItem (); } if (param != NULL) Problem (check_template_arguments, "Not enough template arguments: " + get_full_item_name (temp) + ", missing parameter " + param->name); } /**************************** EXPAND TEMPLATES ****************************/ void expand_namespace (CttNamespace * ns) { // !? CttNamespace * n = introduce_namespace (ns->name); open_scope_and_context (n); expand_scope (ns); close_scope_and_context (); } void expand_class (CttClass * cls) { if (show_detail_messages) info ("expand_class " + get_full_item_name (cls)); CttClass * n = introduce_class_type (cls->class_decl, NULL, context->current_eval); open_scope_and_context (n); CttBase * base = cls->getFirstBase (); while (base != NULL) { create_class_base (base->base_decl); base = base->getNextBase (); } expand_scope (cls); close_scope_and_context (); if (show_detail_messages) info ("end of expand_class " + get_full_item_name (cls)); } void expand_enum_item (CttSimple * enum_item) { introduce_enum_item (enum_item->enum_decl); } void expand_enum (CttEnum * enum_type) { CttEnum * n = introduce_enum_type (enum_type->enum_decl); open_scope_and_context (n); CttItem * item = enum_type->getFirstItem (); while (item != NULL) { CttSimple * simple = item->to_simple (); if (simple != NULL && simple->enum_decl != NULL) expand_enum_item (simple); item = item->getNextItem (); } close_scope_and_context (); } void expand_function (CttFunction * func) { introduce_function_item (func->declarator, NULL, context->current_eval); } void expand_simple (CttSimple * simple) { assert (simple->declarator != NULL); if (simple->declarator != NULL) // !? !! bug introduce_simple_item (simple->declarator); } /* ---------------------------------------------------------------------- */ #if 1 int expand_level = 0; int expand_count = 0; #endif void expand_item (CttItem * item) { assert (item != NULL); if (show_detail_messages) info ("expand_item " + item_description (item) + " " + get_full_item_name (item) + " into " + get_full_item_name (target) /* + " " + NumToHex (item) */ ); // !? !! BUG if (item->expanding) { warning ("BUG: expand_item " + get_full_item_name (item)); // error ("BUG: expand_item " + get_full_item_name (item)); } else { check (!item->expanding); item->expanding = true; #if 1 expand_level ++; check (expand_level <= 100); expand_count ++; check (expand_count <= 200000); #endif CttNamespace * ns = item->to_namespace (); if (ns != NULL) expand_namespace (ns); CttClass * cls = item->to_class (); if (cls != NULL) if (cls->class_decl != NULL) // due to previous errors expand_class (cls); CttEnum * enum_type = item->to_enum (); if (enum_type != NULL) expand_enum (enum_type); // !? CttFunction * func = item->to_function (); if (func != NULL && ! func->is_type) // !? do not expand function types expand_function (func); CttSimple * simple = item->to_simple (); if (simple != NULL) expand_simple (simple); CttFunctionGroup * func_group = item->to_function_group (); if (func_group != NULL) expand_scope (func_group); // !? CttFunctionParams * func_params = item->to_function_params (); if (func_params != NULL) { // expand_scope (func_params); } CttTemplateParams * temp_params = item->to_template_params (); if (temp_params != NULL) { // expand_scope (temp_params); } CttBlock * block = item->to_block (); if (block != NULL) expand_scope (block); #if 1 expand_level --; #endif item->expanding = false; } } void expand_scope (CttScope * scope) { assert (scope != NULL); // if (show_detail_messages) // info ("expand_scope " + get_full_item_name (scope) + " " + NumToHex (scope)); CttItem * item = scope->getFirstItem (); while (item != NULL) { expand_item (item); item = item->getNextItem (); } // if (show_detail_messages) // info ("end of expand_scope " + get_full_item_name (scope) + " " + NumToHex (scope)); } /**************************** MEMBER POINTERS *****************************/ // method called from ckit.g void CmmParser::member_pointer_list (CmmPtrSpecifierSect * sect) { assert (context->current_name == NULL); bool stop = false; while (! stop) { // look for global type name "::" '*' bool ok = false; if (symbol(IDENT)) { // NO CttContext * ctx = open_temporary_context (); CmmMark inx = mark (); // mark point in source code save_trace (); try { if (symbol (SCOPE)) match (SCOPE); identifier (); // if (symbol (LESS)) // template_arg_list (); while (symbol (SCOPE) && LA(2) != STAR) { match (SCOPE); identifier (); // if (symbol (LESS)) // template_arg_list (); } if (symbol (SCOPE) && LA(2) == STAR) ok = true; } catch (IOException & e) { ok = false; } restore_trace (); rewind (inx); // NO close_temporary_context (ctx); } if (ok) { // CttContext * ctx = open_temporary_context (); CmmName * name = new CmmName; open_type_name (name); global_mark (name); open_name (name); base_name (name); start_name (name); base_args (name); while (symbol (SCOPE) && LA(2) != STAR) { name->add (cont_item ()); } close_name (name); close_type_name (name); verify_type (name); // add member pointer to list CmmPtrSpecifier * item = new CmmPtrSpecifier; item->area = name; member_specifier_tail (item); assert (item->member_pointer); sect->add (item); // close_temporary_context (ctx); } else if (symbol (STAR) || symbol (BIT_AND)) { sect->add (ptr_specifier ()); } else { stop = true; } } assert (context->current_name == NULL); } // method called from cmm_product.h void CmmProduct::send_ptr_specifier_list (CmmPtrSpecifierSect * sect) { assert (sect != NULL); CmmPtrSpecifier * item = sect->first; while (item != NULL) { if (item->member_pointer) send_member_specifier (item); else send_ptr_specifier (item); item = item->next; } } /***************************** IDENTIFY NAMES *****************************/ // methods called from ckit.g void CmmParser::open_name (CmmName * name) { check (context->current_name == NULL); // !? !! context->current_name = name; } void CmmParser::start_name (CmmName * name) { CttItem * n = NULL; if (! context->current_new_name || symbol (LESS) || symbol (SCOPE)) n = resolve_base_name (name); // add name into list of references if (n != NULL) link_usage (n, name); assert (context->current_name == name); name->base_ref = n; // important while (n != NULL && n->alias_ref != NULL) n = n->alias_ref; name->name_ref = n; } void CmmParser::add_name (CmmContName * cont) { CmmName * active_name = context->current_name; assert (active_name != NULL); CttItem * n = NULL; if (! context->current_new_name || symbol (LESS) || symbol (SCOPE)) n = resolve_cont_name (active_name->name_ref, cont); if (n != NULL) link_usage (n, cont); cont->cont_ref = n; active_name->name_ref = n; } void CmmParser::close_name (CmmName * name) { context->current_name = NULL; } /* new name */ void CmmParser::open_new_name (CmmName * name) { check (context->current_new_name == false); context->current_new_name = true; } void CmmParser::close_new_name (CmmName * name) { context->current_new_name = false; } /* type name */ void CmmParser::open_type_name (CmmName * name) { check (context->current_typename_prefix == false); context->current_typename_prefix = true; } void CmmParser::close_type_name (CmmName * name) { context->current_typename_prefix = false; } /* "template" keyword after "." or "->" */ void CmmParser::open_field_template (CmmFieldExpr * item) { assert (context->current_template_prefix == false); context->current_template_prefix = item->template_name; } void CmmParser::close_field_template (CmmFieldExpr * item) { context->current_template_prefix = false; } void CmmParser::open_ptr_field_template (CmmPtrFieldExpr * item) { assert (context->current_template_prefix == false); context->current_template_prefix = item->template_name; } void CmmParser::close_ptr_field_template (CmmPtrFieldExpr * item) { context->current_template_prefix = false; } /*************************** IDENTIFY TEMPLATES **************************/ // methods called from ckit.g bool CmmParser::is_template_arg (CmmName * name) { bool answer = false; if (! check_types) { answer = true; } else if (context->current_template_prefix) // template keyword after "." or "->" { answer = true; } else { CmmName * active_name = context->current_name; check (active_name != NULL); CttItem * item = active_name->name_ref; if (item != NULL) answer = item->is_template || item->is_template_group; if (! answer) { Problem (check_templates, "Unknown template: " + compose_qualified_name (name)); answer = true; // !? } } // info ("is_template_arg " + compose_qualified_name (name) + " " + translate_qualified_name (name) + " " + BoolToStr (answer)); return answer; } bool CmmParser::is_cont_template_arg (CmmContName * cont) { bool answer = false; if (! check_types) { answer = true; } else if (cont->a_template || context->current_template_prefix) { answer = true; } else { CmmName * active_name = context->current_name; check (active_name != NULL); CttItem * item = active_name->name_ref; check (item == cont->cont_ref); if (item != NULL) answer = item->is_template || item->is_template_group; if (! answer) { Problem (check_templates, "Unknown template: " + compose_cont_name (cont)); answer = true; // !? } // info ("is_cont_template_arg " + BoolToStr (answer)); } return answer; } /***************************** IDENTIFY TYPES *****************************/ // auxiliary method bool CmmParser::examine_type_name (CmmName * name) { bool answer = false; if (! check_types) { answer = true; } else { CttItem * item = decode_name (name); answer = (item != NULL && item->is_type); // !? unexpanded template class in another template // if (! answer) // info ("examine_type_name " + compose_qualified_name (name) + " " + translate_qualified_name (name) + " " + NumToHex (item) + " " + BoolToStr (answer)); } return answer; } /* ---------------------------------------------------------------------- */ // method called from ckit.g void CmmParser::verify_type (CmmName * name) // verify that identifier is really a type ( not necessary for parsing ) { bool t = examine_type_name (name); if (! t) { // string n = compose_qualified_name (name); // qualified name as string string n = translate_qualified_name (name); Problem (check_types && check_all_types, "Type expected: " + n); } } /* ---------------------------------------------------------------------- */ // auxiliary method bool CmmParser::examine_type_or_declaration (bool decl, bool parenthesis, bool common) { // info ("EXAMINE_TYPE_OR_DECLARATION (begin)"); check (context->current_name == NULL); bool answer = false; int inx = parenthesis ? 2 : 1; switch (LA (inx)) { case LITERAL_const: case LITERAL_volatile: case LITERAL_typename: case LITERAL_signed: case LITERAL_unsigned: case LITERAL_short: case LITERAL_long: case LITERAL_bool: case LITERAL_char: case LITERAL_wchar_t: case LITERAL_int: case LITERAL_float: case LITERAL_double: case LITERAL_void: case LITERAL_extern: case LITERAL_enum: case LITERAL_class: case LITERAL_struct: case LITERAL_union: { answer = true; break; } case LITERAL_typedef: case LITERAL_friend: case LITERAL_inline: case LITERAL_virtual: case LITERAL_explicit: case LITERAL_mutable: case LITERAL_static: case LITERAL_auto: case LITERAL_register: case LITERAL_operator: { answer = decl; break; } case SCOPE: case IDENT: { // CmmName * a = NULL; CttContext * ctx = open_temporary_context (); CmmMark inx = mark (); // mark point in source code save_trace (); try { if (parenthesis) match (LPAREN); // skip parenthesis // !? !! BUG // a = global_name (); if (!decl && common) common_type_id (); // allow identifiers in declarators else type_id (); // declarator without identifiers if (parenthesis) match (RPAREN); answer = true; } catch (IOException & e) { answer = false; } restore_trace (); rewind (inx); // back to original point close_temporary_context (ctx); /* if (a != NULL) answer = examine_type_name (a); */ break; } default: break; } // info ("EXAMINE_TYPE_OR_DECLARATION (end) " + BoolToStr (answer)); return answer; } /* ---------------------------------------------------------------------- */ // methods called from ckit.g bool CmmParser::is_declaration () { return examine_type_or_declaration (true, false, false); /* decl, parenthesis, common_declarator */ } bool CmmParser::is_type () { return examine_type_or_declaration (false, false, false); /* decl, parenthesis, common_declarator */ } bool CmmParser::is_parameter () { if (inside_class) return true; if (LA(1) == RPAREN) return true; // empty parameter list else if (LA(1) == DOTS) return true; else return examine_type_or_declaration (false, false, true); /* decl, parenthesis, common_declarator */ } bool CmmParser::is_initializer_acceptable () { return ! inside_class; } bool CmmParser::is_width_acceptable (CmmDeclarator * decl) { assert (context->current_decl != NULL); return context->current_decl->conv_CmmCtorDecl () == NULL; } bool CmmParser::is_parenthesis_and_expression () { if (LA(1) == LPAREN) return ! examine_type_or_declaration (false, true, false); /* decl, parenthesis, common_declarator */ else return false; } bool CmmParser::is_inner_abstract_declarator () { if (LA(1) == LPAREN) { // !? !! more parenthesis return ! examine_type_or_declaration (false, true, false); /* decl, parenthesis, common_declarator */ } else { return false; } } bool CmmParser::is_inner_common_declarator () { if (LA(1) == LPAREN) { // !? !! more parenthesis return ! examine_type_or_declaration (false, true, true); /* decl, parenthesis, common_declarator */ } else { return false; } } /* ---------------------------------------------------------------------- */ // methods called from ckit.g bool CmmParser::is_type_in_parenthesis () { bool answer = false; if (! check_types) { answer = false; } else { if (LA(1) == LPAREN) answer = examine_type_or_declaration (false, true, false); /* decl, parenthesis, common_declarator */ else answer = false; } if (answer) // is it really type in parenthesis { CttContext * ctx = open_temporary_context (); CmmMark inx = mark (); // mark point in source code save_trace (); try { match (LPAREN); type_id (); match (RPAREN); } catch (IOException & e) { answer = false; } restore_trace (); rewind (inx); // back to original point close_temporary_context (ctx); } return answer; } bool CmmParser::is_constructor () { bool answer = true; CttContext * ctx = open_temporary_context (); CmmMark inx = mark (); // mark point in source code save_trace (); try { constructor_head (); } catch (IOException & e) { answer = false; } restore_trace (); rewind (inx); // back to original point close_temporary_context (ctx); // info ("IS_CONSTRUCTOR = " + BoolToStr (answer)); return answer; } CLOSE_NAMESPACE