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))
28using namespace loggers;
29
30using namespace basis;
31using namespace structures;
32using namespace textual;
33
34namespace nodes {
35
36//hmmm: used for... explain please.
37class symbol_tree_associations : public symbol_table<symbol_tree *>
38{
39public:
40 symbol_tree_associations(int 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
52symbol_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
76int symbol_tree::children() const { return _associations->symbols(); }
77
78const astring &symbol_tree::name() const { return *_name; }
79
80int symbol_tree::estimated_elements() const { return _associations->estimated_elements(); }
81
82void symbol_tree::rehash(int estimated_elements) { _associations->rehash(estimated_elements); }
83
84void 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?
208astring 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
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;
250
251 curr = (tree *)ted.next();
252 }
253
254 return to_return;
255}
256
257} // namespace.
258
#define LOG(s)
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.
symbol_tree(const basis::astring &node_name, int estimated_elements=100)
creates a symbol_tree node with the "node_name".
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".
void hash_appropriately(int estimated_elements)
resizes the hashing parameter to limit bucket sizes.
bool add(symbol_tree *to_add)
adds a child to this symbol_tree.
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.
virtual ~symbol_tree()
all child nodes will be deleted too.
symbol_tree * branch(int index) const
returns the "index"th branch.
void rehash(int estimated_elements)
resizes the underlying symbol_table for this node.
int estimated_elements() const
returns the number of bits in this node's table.
int children() const
returns the number of children of this node.
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.
int estimated_elements() const
returns the number of symbols the table is optimized for.
static const char * platform_eol_to_chars()
provides the characters that make up this platform's line ending.
static basis::astring indentation(int spaces)
Returns a string made of white space that is "spaces" long.
#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:54
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