// If the names of all children have the form (PREFIX)(INDEX)(SUFFIX), // return the common PREFIX and SUFFIX. void DispValue::get_index_surroundings(string& prefix, string& suffix) const { assert (nchildren() > 0); prefix = child(0)->full_name(); suffix = child(0)->full_name(); for (int i = 1; i < nchildren(); i++) { prefix = common_prefix(prefix, child(i)->full_name()); suffix = common_suffix(suffix, child(i)->full_name()); } }
// Clear box caches for this and all children void DispValue::clear_box_cache() { clear_cached_box(); for (int i = 0; i < nchildren(); i++) child(i)->clear_box_cache(); }
// Representation invariant bool ListBox::OK() const { assert (CompositeBox::OK()); assert (nchildren() == 0 || nchildren() == 2); // _last may be inconsistent; it is recomputed before every access // assert (_last && _last->isEmpty()); if (nchildren() == 2) { assert (head() && head()->OK()); assert (tail() && tail()->OK()); } return true; }
int DispValue::nchildren_with_repeats() const { int sum = 0; for (int i = 0; i < nchildren(); i++) sum += child(i)->repeats(); return sum; }
void DispValue::validate_box_cache() { int i; for (i = 0; i < nchildren(); i++) child(i)->validate_box_cache(); for (i = 0; i < nchildren(); i++) { if (child(i)->cached_box() == 0 || child(i)->_cached_box_change > _cached_box_change) { clear_cached_box(); break; } } }
// Check for equality bool CompositeBox::matches (const Box &b, const Box *) const { // Don't compare size and extend, as MatchBoxen have zero size if (strcmp(type(), b.type())) return false; const CompositeBox *c = (const CompositeBox *)&b; // dirty trick if (nchildren() != c->nchildren()) return false; for (int i = 0; i < nchildren(); i++) if (*((*this)[i]) != *((*c)[i])) return false; return true; }
// Count MatchBoxes void CompositeBox::countMatchBoxes(int instances[]) const { for (int i = 0; i < nchildren(); i++) { const Box *child = (*this)[i]; child->countMatchBoxes(instances); } }
TypeSpec ASTindex::typecheck (TypeSpec expected) { typecheck_children (); const char *indextype = ""; TypeSpec t = lvalue()->typespec(); if (t.is_structure()) { error ("Cannot use [] indexing on a struct"); return TypeSpec(); } if (t.is_closure()) { error ("Cannot use [] indexing on a closure"); return TypeSpec(); } if (index3()) { if (! t.is_array() && ! t.elementtype().is_matrix()) error ("[][][] only valid for a matrix array"); m_typespec = TypeDesc::FLOAT; } else if (t.is_array()) { indextype = "array"; m_typespec = t.elementtype(); if (index2()) { if (t.aggregate() == TypeDesc::SCALAR) error ("can't use [][] on a simple array"); m_typespec = TypeDesc::FLOAT; } } else if (t.aggregate() == TypeDesc::VEC3) { indextype = "component"; TypeDesc tnew = t.simpletype(); tnew.aggregate = TypeDesc::SCALAR; tnew.vecsemantics = TypeDesc::NOXFORM; m_typespec = tnew; if (index2()) error ("can't use [][] on a %s", type_c_str(t)); } else if (t.aggregate() == TypeDesc::MATRIX44) { indextype = "component"; TypeDesc tnew = t.simpletype(); tnew.aggregate = TypeDesc::SCALAR; tnew.vecsemantics = TypeDesc::NOXFORM; m_typespec = tnew; if (! index2()) error ("must use [][] on a matrix, not just []"); } else { error ("can only use [] indexing for arrays or multi-component types"); return TypeSpec(); } // Make sure the indices (children 1+) are integers for (size_t c = 1; c < nchildren(); ++c) if (! child(c)->typespec().is_int()) error ("%s index must be an integer, not a %s", indextype, type_c_str(index()->typespec())); // If the thing we're indexing is an lvalue, so is the indexed element m_is_lvalue = lvalue()->is_lvalue(); return m_typespec; }
void ASTvariable_ref::print (std::ostream &out, int indentlevel) const { indent (out, indentlevel); out << "(" << nodetypename() << " (type: " << (m_sym ? m_sym->typespec().string() : "unknown") << ") " << (m_sym ? m_sym->mangled() : m_name.string()) << ")\n"; DASSERT (nchildren() == 0); }
// Return height of entire tree int DispValue::height() const { int d = 0; for (int i = 0; i < nchildren(); i++) d = max(d, child(i)->height()); return d + 1; }
// Propagate font void CompositeBox::newFont(const string& font) { for (int i = 0; i < nchildren(); i++) { Box* child = (*this)[i]; child->newFont(font); } resize(); }
// Recompute size Box *CompositeBox::resize() { for (int i = 0; i < nchildren(); i++) { Box* child = (*this)[i]; child->resize(); } return this; }
// Count expanded nodes in tree int DispValue::expandedAll() const { int count = 0; if (expanded()) count++; for (int i = 0; i < nchildren(); i++) count += child(i)->expandedAll(); return count; }
// Create string from Box string CompositeBox::str() const { string s(""); for (int i = 0; i < nchildren(); i++) { const Box* child = (*this)[i]; s += child->str(); } return s; }
// Count collapsed nodes in tree int DispValue::collapsedAll() const { int count = 0; if (collapsed()) count++; for (int i = 0; i < nchildren(); i++) count += child(i)->collapsedAll(); return count; }
// Return true iff this or some descendant changed bool DispValue::descendant_changed() const { if (changed) return true; for (int i = 0; i < nchildren(); i++) if (child(i)->descendant_changed()) return true; return false; }
// Expand. Like expand(), but expand entire subtree void DispValue::expandAll(int depth) { if (depth == 0) return; _expand(); for (int i = 0; i < nchildren(); i++) { child(i)->expandAll(depth - 1); } }
// Collapse. Like collapse(), but collapse entire subtree void DispValue::collapseAll(int depth) { if (depth == 0) return; _collapse(); for (int i = 0; i < nchildren(); i++) { child(i)->collapseAll(depth - 1); } }
// Find TagBox for point P const TagBox *CompositeBox::findTag(const BoxPoint& p) const { if (p != BoxPoint(-1, -1)) for (int i = 0; i < nchildren(); i++) { const Box *child = (*this)[i]; const TagBox *t = child->findTag(p); if (t != 0) return t; // found } return 0; // not found }
// Dump void CompositeBox::dumpComposite(std::ostream& s, const char *sep, const char *head, const char *tail) const { s << head; for (int i = 0; i < nchildren(); i++) { const Box* child = (*this)[i]; if (i > 0) s << sep; s << *child; } s << tail; }
// // Constructor: reads taxonomy file and builds taxonomy as a DAG // Taxonomy::Taxonomy(LINT num_items, // total number of items LINT num_roots, // number of roots FLOAT fanout, // average fanout FLOAT depth_ratio // average ratio of .... ) : nitems(num_items), nroots(num_roots), depth(depth_ratio) { LINT i, j; LINT next_child; PoissonDist nchildren(fanout-1); // string length // allocate memory par = new LINT [nitems]; child_start = new LINT [nitems]; child_end = new LINT [nitems]; next_child = nroots; // initialize parents (or lack thereof) for roots for (i = 0; i < nroots; i++) par[i] = -1; // set up all the interior nodes for (i = 0, j = next_child; i < nitems && next_child < nitems; i++) { child_start[i] = next_child; next_child += nchildren() + 1; if (next_child > nitems) next_child = nitems; child_end[i] = next_child; for (; j < next_child; j++) par[j] = i; } // initialize children (or lack thereof) for all the leaves for (; i < nitems; i++) child_start[i] = child_end[i] = -1; }
bool DispValue::can_plot2d() const { if (type() == Array) { for (int i = 0; i < nchildren(); i++) { if (!child(i)->can_plot1d()) return false; } return true; } if (nchildren() > 0) { // If we have a list of indexed names, then we can plot in 2d. int i; string prefix, suffix; get_index_surroundings(prefix, suffix); for (i = 0; i < nchildren(); i++) { string idx = child(i)->index(prefix, suffix); if (!idx.matches(rxdouble) && !idx.matches(rxint)) return false; } for (i = 0; i < nchildren(); i++) { if (!child(i)->can_plot1d()) return false; } return true; } return false; }
// Destructor helper void DispValue::clear() { for (int i = 0; i < nchildren(); i++) child(i)->unlink(); static const DispValueArray empty(0); _children = empty; if (plotter() != 0) { plotter()->terminate(); _plotter = 0; } clear_cached_box(); }
// Return height of expanded tree int DispValue::heightExpanded() const { if (collapsed()) return 0; int d = 0; for (int i = 0; i < nchildren(); i++) { if (child(i)->collapsed()) return 1; d = max(d, child(i)->heightExpanded()); } return d + 1; }
int DispValue::can_plot() const { if (can_plot3d()) return 3; if (can_plot2d()) return 2; if (can_plot1d()) return 1; // Search for plottable array children int ndim = 0; for (int i = 0; i < nchildren(); i++) ndim = max(ndim, child(i)->can_plot()); return ndim; }
bool DispValue::can_plot3d() const { if (type() != Array) return false; int grandchildren = -1; for (int i = 0; i < nchildren(); i++) { if (!child(i)->can_plot2d()) return false; if (i == 0) grandchildren = child(i)->nchildren_with_repeats(); else if (child(i)->nchildren_with_repeats() != grandchildren) return false; // Differing number of grandchildren } return true; }
DispValue *DispValue::_update(DispValue *source, bool& was_changed, bool& was_initialized) { if (source == this) { // We're updated from ourselves -- ignore it all. // This happens when a cluster is updated from the values of // the clustered dislays. if (descendant_changed()) was_changed = true; return this; } if (changed) { // Clear `changed' flag changed = false; was_changed = true; } if (source->enabled() != enabled()) { myenabled = source->enabled(); was_changed = true; // We don't set CHANGED to true since enabled/disabled changes // are merely a change in the view, not a change in the data. } if (source->full_name() == full_name() && source->type() == type()) { switch (type()) { case Simple: case Text: case Pointer: // Atomic values if (_value != source->value()) { _value = source->value(); changed = was_changed = true; } return this; case Array: // Array. Check for 1st element, too. if (_have_index_base != source->_have_index_base && (_have_index_base && _index_base != source->_index_base)) break; // FALL THROUGH case Reference: case Sequence: // Numbered children. If size changed, we assume // the whole has been changed. if (nchildren() == source->nchildren()) { for (int i = 0; i < nchildren(); i++) { // Update each child _children[i] = child(i)->update(source->child(i), was_changed, was_initialized); } return this; } break; case List: case Struct: { // Named children. Check whether names are the same. bool same_members = (nchildren() == source->nchildren()); for (int i = 0; same_members && i < nchildren(); i++) { if (child(i)->full_name() != source->child(i)->full_name()) same_members = false; } if (same_members) { // Update each child for (int i = 0; i < nchildren(); i++) { _children[i] = child(i)->update(source->child(i), was_changed, was_initialized); } return this; } // Members have changed. // Be sure to mark only those members that actually have changed // (i.e. don't mark the entire struct and don't mark new members) // We do so by creating a new list of children. `Old' children // that still are reported get updated; `new' children are added. DispValueArray new_children; DispValueArray processed_children; for (int j = 0; j < source->nchildren(); j++) { DispValue *c = 0; for (int i = 0; c == 0 && i < nchildren(); i++) { bool processed = false; for (int k = 0; k < processed_children.size(); k++) { if (child(i) == processed_children[k]) processed = true; } if (processed) continue; if (child(i)->full_name() == source->child(j)->full_name()) { c = child(i)->update(source->child(j), was_changed, was_initialized); processed_children += child(i); } } if (c == 0) { // Child not found -- use source child instead c = source->child(j)->link(); } new_children += c; } _children = new_children; was_changed = was_initialized = true; return this; } case UnknownType: assert(0); abort(); } } // Type, name or structure have changed -- use SOURCE instead of original DispValue *ret = source->link(); ret->changed = was_changed = was_initialized = true; // Copy the basic settings ret->myexpanded = expanded(); ret->dereference(dereferenced()); ret->set_orientation(orientation()); ret->set_member_names(member_names()); // Have new DispValue take over the plotter if (ret->plotter() == 0) { ret->_plotter = plotter(); _plotter = 0; } unlink(); return ret; }
// Return true iff SOURCE and this are structurally equal. // If SOURCE_DESCENDANT (a descendant of SOURCE) is set, // return its equivalent descendant of this in DESCENDANT. bool DispValue::structurally_equal(const DispValue *source, const DispValue *source_descendant, const DispValue *&descendant) const { if (source == source_descendant) descendant = this; if (type() != source->type()) return false; // Differing type switch (type()) { case Simple: case Text: case Pointer: return true; // Structurally equal case Array: { if (nchildren() != source->nchildren()) return false; // Differing size if (_have_index_base != source->_have_index_base) return false; // Differing base if (_have_index_base && _index_base != source->_index_base) return false; // Differing base for (int i = 0; i < nchildren(); i++) { DispValue *child = _children[i]; DispValue *source_child = source->child(i); bool eq = child->structurally_equal(source_child, source_descendant, descendant); if (!eq) return false; } return true; // All children structurally equal } case List: case Struct: case Sequence: case Reference: { if (nchildren() != source->nchildren()) return false; for (int i = 0; i < nchildren(); i++) { DispValue *child = _children[i]; DispValue *source_child = source->child(i); bool eq = child->structurally_equal(source_child, source_descendant, descendant); if (!eq) return false; } return true; // All children structurally equal } case UnknownType: assert(0); abort(); } return false; // Not found }
// Initialization void DispValue::init(DispValue *parent, int depth, string& value, DispValueType given_type) { #if LOG_CREATE_VALUES std::clog << "Building value from " << quote(value) << "\n"; #endif // Be sure the value is not changed in memory value.consuming(true); const char *initial_value = value.chars(); static const DispValueArray empty(0); _children = empty; if (background(value.length())) { clear(); mytype = Simple; _value = "(Aborted)"; value = "Aborted\n"; return; } mytype = given_type; if (mytype == UnknownType && (parent == 0 || parent->type() == List) && print_name.empty()) mytype = Text; if (mytype == UnknownType && parent == 0 && is_user_command(print_name)) mytype = List; if (mytype == UnknownType) mytype = determine_type(value); bool ignore_repeats = (parent != 0 && parent->type() == Array); char perl_type = '\0'; switch (mytype) { case Simple: { _value = read_simple_value(value, depth, ignore_repeats); #if LOG_CREATE_VALUES std::clog << mytype << ": " << quote(_value) << "\n"; #endif perl_type = '$'; break; } case Text: { // Read in a line of text if (value.contains('\n')) _value = value.through('\n'); else _value = value; value = value.after('\n'); #if LOG_CREATE_VALUES std::clog << mytype << ": " << quote(_value) << "\n"; #endif perl_type = '$'; break; } case Pointer: { _value = read_pointer_value(value, ignore_repeats); _dereferenced = false; #if LOG_CREATE_VALUES std::clog << mytype << ": " << quote(_value) << "\n"; #endif // Hide vtable pointers. if (_value.contains("virtual table") || _value.contains("vtable")) myexpanded = false; perl_type = '$'; // In Perl, pointers may be followed by indented `pointed to' // info. Skip this. if (gdb->type() == PERL) { while (value.contains("\n ", 0)) { value = value.after("\n "); value = value.from("\n"); } } break; } case Array: { string base = normalize_base(myfull_name); _orientation = app_data.array_orientation; #if LOG_CREATE_VALUES std::clog << mytype << ": " << "\n"; #endif read_array_begin(value, myaddr); // Check for `vtable entries' prefix. string vtable_entries = read_vtable_entries(value); if (!vtable_entries.empty()) { _children += parse_child(depth, vtable_entries, myfull_name); } // Read the array elements. Assume that the type is the // same across all elements. DispValueType member_type = UnknownType; if (!_have_index_base) { _index_base = index_base(base, depth); _have_index_base = true; } int array_index = _index_base; // The array has at least one element. Otherwise, GDB // would treat it as a pointer. do { const char *repeated_value = value.chars(); string member_name = gdb->index_expr("", itostring(array_index++)); DispValue *dv = parse_child(depth, value, add_member_name(base, member_name), member_name, member_type); member_type = dv->type(); _children += dv; int repeats = read_repeats(value); if (expand_repeated_values) { // Create one value per repeat while (--repeats > 0) { member_name = gdb->index_expr("", itostring(array_index++)); string val = repeated_value; DispValue *repeated_dv = parse_child(depth, val, add_member_name(base, member_name), member_name, member_type); _children += repeated_dv; } } else { // Show repetition in member if (repeats > 1) { array_index--; #if 0 // We use the GDB `artificial array' notation here, // since repeat recognition is supported in GDB only. member_name += "@" + itostring(repeats); dv->full_name() = add_member_name(base, member_name); dv->name() = member_name; #endif dv->repeats() = repeats; array_index += repeats; } } if (background(value.length())) { init(parent, depth, value); return; } } while (read_array_next(value)); read_array_end(value); // Expand only if at top-level. myexpanded = (depth == 0 || nchildren() <= 1); #if LOG_CREATE_VALUES std::clog << mytype << " has " << nchildren() << " members\n"; #endif perl_type = '@'; break; } case List: // Some DBXes issue the local variables via a frame line, just // like `set_date(d = 0x10003060, day_of_week = Sat, day = 24, // month = 12, year = 1994)'. Make this more readable. munch_dump_line(value); // FALL THROUGH case Struct: { _orientation = app_data.struct_orientation; _member_names = app_data.show_member_names; bool found_struct_begin = false; bool read_multiple_values = false; #if LOG_CREATE_VALUES std::clog << mytype << " " << quote(myfull_name) << "\n"; #endif string member_prefix = myfull_name; string member_suffix = ""; if (mytype == List) { member_prefix = ""; read_multiple_values = true; } else { // In C and Java, `*' binds tighter than `.' if (member_prefix.contains('*', 0)) { if (gdb->program_language() == LANGUAGE_C) { // Use the C `->' operator instead member_prefix.del("*"); if (member_prefix.contains('(', 0) && member_prefix.contains(')', -1)) member_prefix = unquote(member_prefix); #if RUNTIME_REGEX static regex rxchain("[-a-zA-Z0-9::_>.`]+"); #endif if (member_prefix.matches(rxchain)) { // Simple chain of identifiers - prepend `->' member_prefix += "->"; } else { member_prefix.prepend("("); member_prefix += ")->"; } } else { member_prefix.prepend("("); member_prefix += ")."; } } else if (gdb->program_language() == LANGUAGE_PERL) { // In Perl, members of A are accessed as A{'MEMBER_NAME'} member_prefix = normalize_base(member_prefix) + "{'"; member_suffix = "'}"; } else if (gdb->program_language() == LANGUAGE_PHP) { // In PHP, members of $A are accessed as $A['MEMBER_NAME'] member_prefix = normalize_base(member_prefix) + "['"; member_suffix = "']"; } else if (gdb->program_language() == LANGUAGE_FORTRAN) { // In Fortran, members of A are accessed as A%B member_prefix = normalize_base(member_prefix) + "%"; } else { // In all other languages, members are accessed as A.B member_prefix = normalize_base(member_prefix) + "."; } // In case we do not find a struct beginning, read only one value found_struct_begin = read_struct_begin(value, myaddr); read_multiple_values = found_struct_begin; } // Prepend base class in case of multiple inheritance // FIXME: This should be passed as an argument static string baseclass_prefix; member_prefix += baseclass_prefix; int base_classes = 0; bool more_values = true; while (more_values) { // In a List, we may have `member' names like `(a + b)'. // Don't be picky about this. bool picky = (mytype == Struct); string member_name = read_member_name(value, picky); if (member_name.empty()) { // Some struct stuff that is not a member DispValue *dv = parse_child(depth, value, myfull_name, ""); if (dv->type() == Struct) { // What's this - a struct within a struct? Just // adopt the members. // (This happens when we finally found the struct // after having read all the AIX DBX base classes.) for (int i = 0; i < dv->nchildren(); i++) { DispValue *dv2 = dv->child(i)->link(); _children += dv2; } dv->unlink(); } else { _children += dv; } more_values = read_multiple_values && read_struct_next(value); } else if (is_BaseClass_name(member_name)) { // Base class member string saved_baseclass_prefix = baseclass_prefix; base_classes++; if (base_classes > 1) { // Multiple inheritance. Be sure to // reference further members unambiguously. // // Note: we don't do that for the first base class, // because this might turn ambiguous again. // // Example: // // Base // | | // I1 I2 // \ / // C // // Members of I1::Base are not prefixed, members // of I2::Base get `I2::' as base class prefix. // If we did this already for the first base class, // members of both I1 and I2 would get `Base::' as // base class prefix. switch (gdb->program_language()) { case LANGUAGE_C: // C++ baseclass_prefix = unquote(member_name) + "::"; break; default: // Do nothing (yet) break; } } DispValue *dv = parse_child(depth, value, myfull_name, member_name); _children += dv; baseclass_prefix = saved_baseclass_prefix; more_values = read_multiple_values && read_struct_next(value); // Skip a possible `members of CLASS:' prefix read_members_prefix(value); // AIX DBX does not place a separator between base // classes and the other members, so we always // continue reading after having found a base // class. After all, the own class members are // still missing. if (mytype == Struct && !found_struct_begin) more_values = true; } else { // Ordinary member string full_name = ""; if (member_name == " ") { // Anonymous union full_name = myfull_name; } if (member_name.contains('.')) { if (gdb->has_quotes()) { // The member name contains `.' => quote it. This // happens with vtable pointers on Linux (`_vptr.'). full_name = member_prefix + quote(member_name, '\'') + member_suffix; } else { // JDB (and others?) prepend the class name // to inherited members. Omit this. full_name = member_prefix + member_name.after('.', -1) + member_suffix; } } if (full_name.empty()) { // Ordinary member full_name = member_prefix + member_name + member_suffix; } DispValue *child = parse_child(depth, value, full_name, member_name); if (child->type() == Text) { // Found a text as child - child value must be empty string empty = ""; _children += parse_child(depth, empty, full_name, member_name); string v = child->value(); strip_space(v); if (!v.empty()) _children += child; } else { _children += child; } more_values = read_multiple_values && read_struct_next(value); } if (background(value.length())) { init(parent, depth, value); return; } } if (mytype == List && !value.empty()) { // Add remaining value as text _children += parse_child(depth, value, ""); } if (found_struct_begin) { // Skip the remainder read_struct_end(value); } // Expand only if at top-level. myexpanded = (depth == 0 || nchildren() <= 1); #if LOG_CREATE_VALUES std::clog << mytype << " " << quote(myfull_name) << " has " << nchildren() << " members\n"; #endif perl_type = '%'; break; } case Reference: { myexpanded = true; int sep = value.index('@'); sep = value.index(':', sep); string ref = value.before(sep); value = value.after(sep); string addr = gdb->address_expr(myfull_name); _children += parse_child(depth, ref, addr, myfull_name, Pointer); _children += parse_child(depth, value, myfull_name); if (background(value.length())) { init(parent, depth, value); return; } perl_type = '$'; // No such thing in Perl... break; } case Sequence: case UnknownType: assert(0); abort(); } // Handle trailing stuff (`sequences') if (parent == 0 || parent->type() != Sequence) { bool need_clear = true; while (sequence_pending(value, parent)) { if (need_clear) { #if LOG_CREATE_VALUES std::clog << "Sequence detected at " << quote(value) << "\n"; #endif clear(); value = initial_value; mytype = Sequence; #if LOG_CREATE_VALUES std::clog << mytype << " " << quote(myfull_name) << "\n"; #endif need_clear = false; } const char *old_value = value.chars(); DispValue *dv = parse_child(depth, value, myfull_name); if (value == old_value) { // Nothing consumed - stop here dv->unlink(); break; } else if (dv->type() == Simple && dv->value().empty()) { // Empty value - ignore dv->unlink(); } else { _children += dv; } } #if LOG_CREATE_VALUES if (!need_clear) { std::clog << mytype << " " << quote(myfull_name) << " has " << nchildren() << " members\n"; } #endif } if (gdb->program_language() == LANGUAGE_PERL && is_perl_prefix(perl_type)) { // Set new type if (!myfull_name.empty() && is_perl_prefix(myfull_name[0])) myfull_name[0] = perl_type; } background(value.length()); changed = true; }