feisty meow concerns codebase  2.140
symbol_tree.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : symbol_tree *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 1992-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
15 #include "symbol_tree.h"
16 
17 #include <basis/functions.h>
19 #include <textual/parser_bits.h>
21 
22 //#define DEBUG_SYMBOL_TREE
23  // uncomment for totally noisy version.
24 
26 #undef LOG
27 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), astring(s) + a_sprintf(" [obj=%p]", this))
28 using namespace loggers;
29 
30 using namespace basis;
31 using namespace structures;
32 using namespace textual;
33 
34 namespace nodes {
35 
36 //hmmm: used for... explain please.
37 class symbol_tree_associations : public symbol_table<symbol_tree *>
38 {
39 public:
40  symbol_tree_associations(int estimated_elements)
41  : symbol_table<symbol_tree *>(estimated_elements) {}
42  virtual ~symbol_tree_associations() {
43 //probably we don't actually want to whack here???
44 // for (int i = 0; i < symbols(); i++) {
45 // WHACK(use(i));
46 // }
47  }
48 };
49 
51 
52 symbol_tree::symbol_tree(const astring &node_name, int estimated_elements)
53 : tree(),
54  _associations(new symbol_tree_associations(estimated_elements)),
55  _name(new astring(node_name))
56 {
57  FUNCDEF("constructor")
58 }
59 
61 {
62  FUNCDEF("destructor");
63 #ifdef DEBUG_SYMBOL_TREE
64  LOG("symtree dtor: prior to whacks");
65 #endif
66  WHACK(_associations);
67 #ifdef DEBUG_SYMBOL_TREE
68  LOG("symtree dtor: after whacking associations");
69 #endif
70  WHACK(_name);
71 #ifdef DEBUG_SYMBOL_TREE
72  LOG("symtree dtor: after all whacks");
73 #endif
74 }
75 
76 int symbol_tree::children() const { return _associations->symbols(); }
77 
78 const astring &symbol_tree::name() const { return *_name; }
79 
80 int symbol_tree::estimated_elements() const { return _associations->estimated_elements(); }
81 
82 void symbol_tree::rehash(int estimated_elements) { _associations->rehash(estimated_elements); }
83 
84 void symbol_tree::hash_appropriately(int estimated_elements)
85 { _associations->hash_appropriately(estimated_elements); }
86 
88 {
89 #ifdef DEBUG_SYMBOL_TREE
90  FUNCDEF("add");
91  LOG(astring("adding node for ") + to_add->name());
92 #endif
93  attach(to_add); // add to tree.
94  _associations->add(to_add->name(), to_add); // add to associations.
95  return true;
96 }
97 
99 {
100 #ifdef DEBUG_SYMBOL_TREE
101  FUNCDEF("prune");
102 #endif
103  symbol_tree *to_zap = dynamic_cast<symbol_tree *>(to_zap_in);
104  if (to_zap) {
105 #ifdef DEBUG_SYMBOL_TREE
106  LOG(astring("zapping node for ") + to_zap->name());
107 #endif
108  int found = which(to_zap); // find the node in the tree.
109  if (negative(found)) return common::NOT_FOUND; // not found.
110 #ifdef DEBUG_SYMBOL_TREE
111  int kids = _associations->symbols();
112 #endif
113  _associations->whack(to_zap->name()); // remove from associations.
114 #ifdef DEBUG_SYMBOL_TREE
115  if (kids - 1 != _associations->symbols())
116  throw("error: symbol_tree::prune: failed to crop kid in symtab");
117 #endif
118  } else {
119 #ifdef DEBUG_SYMBOL_TREE
120  LOG("skip symtree prune steps due to null symtree after dynamic cast.");
121 #endif
123  }
124 #ifdef DEBUG_SYMBOL_TREE
125  LOG("about to call base tree::prune...");
126 #endif
127  tree::prune(to_zap); // remove from tree.
128 #ifdef DEBUG_SYMBOL_TREE
129  LOG("after called base tree::prune.");
130 #endif
131  return common::OKAY;
132 }
133 
135 { return dynamic_cast<symbol_tree *>(tree::branch(index)); }
136 
137 // implementation snagged from basis/shell_sort.
139 {
140  int n = branches();
141  symbol_tree *temp;
142  int gap, i, j;
143  for (gap = n / 2; gap > 0; gap /= 2) {
144  for (i = gap; i < n; i++) {
145  for (j = i - gap; j >= 0 && branch(j)->name() > branch(j + gap)->name();
146  j = j - gap) {
147  // swap the elements that are disordered.
148  temp = branch(j + gap);
149  prune_index(j + gap);
150  insert(j, temp);
151  temp = branch(j + 1);
152  prune_index(j + 1);
153  insert(j + gap, temp);
154  }
155  }
156  }
157 }
158 
161 {
162 #ifdef DEBUG_SYMBOL_TREE
163  FUNCDEF("find");
164 #endif
165  if (comp == NULL_POINTER) comp = astring_comparator;
166 #ifdef DEBUG_SYMBOL_TREE
167  LOG(astring("finding node called ") + to_find);
168 #endif
169  // ensure that we compare the current node.
170  if (comp(name(), to_find)) return this;
171 
172  // perform the upward recursion first, since it's pretty simple.
173  if (how == recurse_upward) {
174  symbol_tree *our_parent = dynamic_cast<symbol_tree *>(parent());
175  if (!our_parent) return NULL_POINTER; // done recursing.
176  return our_parent->find(to_find, how, comp);
177  }
178 
179  // see if our branches match the search term.
180  symbol_tree **found = _associations->find(to_find, comp);
181 #ifdef DEBUG_SYMBOL_TREE
182  if (!found) LOG(to_find + " was not found.")
183  else LOG(to_find + " was found successfully.");
184 #endif
185  if (!found) {
186  if (how == recurse_downward) {
187  // see if we can't find that name in a sub-node.
188  symbol_tree *answer = NULL_POINTER;
189  for (int i = 0; i < branches(); i++) {
190  // we will try each branch in turn and see if it has a child named
191  // appropriately.
192  symbol_tree *curr = dynamic_cast<symbol_tree *>(branch(i));
193 #ifdef DEBUG_SYMBOL_TREE
194  LOG(astring("recursing to ") + curr->name());
195 #endif
196  if (curr)
197  answer = curr->find(to_find, how, comp);
198  if (answer)
199  return answer;
200  }
201  }
202  return NULL_POINTER;
203  }
204  return *found;
205 }
206 
207 //hmmm: is this useful elsewhere?
208 astring hier_prefix(int depth, int kids)
209 {
210  astring indent = string_manipulation::indentation( (depth - 1) * 2);
211  if (!depth) return "";
212  else if (!kids) return indent + "|--";
213  else return indent + "+--";
214 }
215 
217 {
218 #ifdef DEBUG_SYMBOL_TREE
219  FUNCDEF("text_form");
220 #endif
221  astring to_return;
222 
223  tree::iterator ted = start(prefix);
224  // create our iterator to do a prefix traversal.
225 
226  tree *curr = (tree *)ted.next();
227 
228 //hmmm: this cast assumes that the tree only contains trees. for more
229 // safety, we might want a dynamic cast here also.
230  while (curr) {
231  // we have a good directory to show.
232  symbol_tree *curr_cast = dynamic_cast<symbol_tree *>(curr);
233  if (!curr_cast) {
234  // something very bad with that...
235 #ifdef DEBUG_SYMBOL_TREE
236  LOG("logic error: unknown type in symbol tree.");
237 #endif
238  ted.next();
239  continue;
240  }
241  astring name_to_log = curr_cast->name();
242  if (!ted.size()) name_to_log = "";
243 #ifdef DEBUG_SYMBOL_TREE
244  LOG(a_sprintf("depth %d kids %d name %s", ted.size(), curr_cast->branches(),
245  name_to_log.s()));
246 #endif
247  to_return += hier_prefix(curr->depth(), curr_cast->branches());
248  to_return += name_to_log;
249  to_return += parser_bits::platform_eol_to_chars();
250 
251  curr = (tree *)ted.next();
252  }
253 
254  return to_return;
255 }
256 
257 } // namespace.
258 
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
Outcomes describe the state of completion for an operation.
Definition: outcome.h:31
int size() const
returns the number of items in the path.
Definition: path.cpp:55
A symbol table that supports scope nesting and/or trees of symbol tables.
Definition: symbol_tree.h:37
void sort()
sorts the sub-nodes of this symbol_tree.
basis::astring text_form() const
traverses the tree to build a textual list of the nodes.
virtual basis::outcome prune(tree *to_zap)
removes a sub-tree "to_zap".
Definition: symbol_tree.cpp:98
void hash_appropriately(int estimated_elements)
resizes the hashing parameter to limit bucket sizes.
Definition: symbol_tree.cpp:84
bool add(symbol_tree *to_add)
adds a child to this symbol_tree.
Definition: symbol_tree.cpp:87
symbol_tree * find(const basis::astring &to_find, find_methods how, basis::string_comparator_function *comp=NULL_POINTER)
returns the node specified by "to_find" or NULL_POINTER.
const basis::astring & name() const
returns the name of this node.
Definition: symbol_tree.cpp:78
virtual ~symbol_tree()
all child nodes will be deleted too.
Definition: symbol_tree.cpp:60
symbol_tree * branch(int index) const
returns the "index"th branch.
void rehash(int estimated_elements)
resizes the underlying symbol_table for this node.
Definition: symbol_tree.cpp:82
int estimated_elements() const
returns the number of bits in this node's table.
Definition: symbol_tree.cpp:80
int children() const
returns the number of children of this node.
Definition: symbol_tree.cpp:76
tree * next()
Returns a pointer to the next tree in the direction of traversal.
Definition: tree.cpp:257
A dynamically linked tree with an arbitrary number of branches.
Definition: tree.h:40
virtual int depth() const
Returns the distance of "this" from the root. The root's depth is 0.
Definition: tree.cpp:502
virtual void insert(int branch_place, tree *new_branch)
inserts "new_branch" before the branches starting at "branch_place".
Definition: tree.cpp:460
virtual basis::outcome prune_index(int branch_to_cut)
Removes the branch at the specified index from this tree.
Definition: tree.cpp:479
virtual int which(tree *branch_to_find) const
Returns the branch number for a particular branch in this tree.
Definition: tree.cpp:440
virtual int branches() const
Returns the number of branches currently connected to this tree.
Definition: tree.cpp:431
virtual void attach(tree *new_branch)
Attaches the specified branch to the current tree.
Definition: tree.cpp:453
virtual basis::outcome prune(tree *branch_to_cut)
Removes the specified branch from this tree.
Definition: tree.cpp:472
virtual tree * parent() const
Returns the tree node that is the immediate ancestor of this one.
Definition: tree.cpp:429
iterator start(traversal_directions direction) const
Returns a fresh iterator positioned at this tree node.
Definition: tree.cpp:542
@ prefix
Definition: tree.h:94
virtual tree * branch(int branch_number) const
Returns the specified branch of this tree.
Definition: tree.cpp:433
Maintains a list of names, where each name has a type and some contents.
Definition: symbol_table.h:36
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
bool string_comparator_function(const astring &a, const astring &b)
returns true if the strings "a" and "b" are considered equal.
Definition: astring.h:449
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition: functions.h:43
bool astring_comparator(const astring &a, const astring &b)
implements a string comparator that just does simple astring ==.
Definition: astring.cpp:53
A logger that sends to the console screen using the standard output device.
astring hier_prefix(int depth, int kids)
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
#define LOG(s)
Definition: symbol_tree.cpp:27