Synopsis - Cross-Reference

File: src/Synopsis/PTree/Display.cc
  1//
  2// Copyright (C) 2004 Stefan Seefeld
  3// All rights reserved.
  4// Licensed to the public under the terms of the GNU LGPL (>= 2),
  5// see the file COPYING for details.
  6//
  7
  8#include <Synopsis/PTree/Display.hh>
  9#include <typeinfo>
 10#include <memory>
 11#include <cstdlib>
 12#if defined(__GNUC__) &&  __GNUC__ >= 3
 13# include <cxxabi.h>
 14
 15# if __GNUC__ == 3 && __GNUC_MINOR__ == 0
 16namespace abi
 17{
 18  extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
 19}
 20# endif 
 21#endif
 22
 23namespace
 24{
 25
 26struct free_mem
 27{
 28  free_mem(char *p) : p(p) {}
 29  ~free_mem() { std::free(p);}
 30  char * p;
 31};
 32
 33std::string demangle(char const *mangled)
 34{
 35#if defined(__GNUC__) &&  __GNUC__ >= 3
 36  std::string demangled;
 37  int status;
 38  free_mem keeper(abi::__cxa_demangle(mangled, 0, 0, &status));
 39  assert(status != -3); // invalid argument error
 40  if (status == -1) { throw std::bad_alloc();}
 41  else
 42    // On failure return the mangled name.
 43    demangled = status == -2 ? mangled : keeper.p;
 44  return demangled.substr(17); // skip 'Synopsis::PTree::' prefix
 45#else
 46  return mangled;
 47#endif
 48}
 49}
 50
 51using namespace Synopsis;
 52using namespace PTree;
 53
 54Display::Display(std::ostream &os, bool encoded)
 55  : my_os(os),
 56    my_indent(0),
 57    my_encoded(encoded)
 58{
 59}
 60
 61void Display::display(Node const *n)
 62{
 63  if (n) const_cast<Node *>(n)->accept(this);
 64  else my_os << "nil";
 65  my_os.put('\n');
 66}
 67
 68void Display::visit(Atom *a)
 69{
 70  char const *p = a->position();
 71  size_t n = a->length();
 72
 73  // Recall that [, ], and @ are special characters.
 74
 75  if(n < 1) return;
 76  else if(n == 1 && *p == '@')
 77  {
 78    my_os << "\\@";
 79    return;
 80  }
 81
 82  char c = *p++;
 83  if(c == '[' || c == ']') my_os << '\\' << c; // [ and ] at the beginning are escaped.
 84  else my_os << c;
 85  while(--n > 0) my_os << *p++;
 86}
 87
 88void Display::visit(List *l) 
 89{
 90  Node *rest = l;
 91  my_os << '[';
 92  while(rest != 0)
 93  {
 94    if(rest->is_atom())
 95    {
 96      my_os << "@ ";
 97      rest->accept(this);
 98      rest = 0;
 99    }
100    else
101    {
102      Node *head = rest->car();
103      if(head == 0) my_os << "nil";
104      else
105      {
106	head->accept(this);
107      }
108      rest = rest->cdr();
109      if(rest != 0) my_os << ' ';
110    }
111  }
112  my_os << ']';
113}
114
115void Display::visit(DupAtom *a)
116{
117  char const *pos = a->position();
118  size_t length = a->length();
119
120  if(length == 1 && *pos == '@')
121  {
122    my_os << "\\@";
123    return;
124  }
125
126  my_os << '`';
127  for(size_t i = 0; i < length; ++i)
128    if(pos[i] == '[' || pos[i] == ']') my_os << '\\' << pos[i];
129    else my_os << pos[i];
130  my_os << '`';
131}
132
133void Display::visit(Brace *l)
134{
135  ++my_indent;
136  my_os << "[{";
137  Node *body = second(l);
138  if(!body)
139  {
140    newline();
141    my_os << "nil";
142  }
143  else
144    while(body)
145    {
146      newline();
147      if(body->is_atom())
148      {
149	my_os << "@ ";
150	body->accept(this);
151      }
152      else
153      {
154	Node *head = body->car();
155	if(!head) my_os << "nil";
156	else
157	{
158	  head->accept(this);
159	}
160      }
161      body = body->cdr();
162    }
163  --my_indent;
164  newline();
165  my_os << "}]";
166}
167
168void Display::newline()
169{
170  my_os.put('\n');
171  for(size_t i = 0; i != my_indent; ++i) my_os.put(' ');
172}
173
174void Display::print_encoded(List *l)
175{
176  if (my_encoded)
177  {
178    Encoding const &type = l->encoded_type();
179    if(!type.empty()) my_os << '#' << type;
180    Encoding const &name = l->encoded_name();
181    if(!name.empty()) my_os << '@' << name;
182  }
183  visit(static_cast<List *>(l));
184}
185
186RTTIDisplay::RTTIDisplay(std::ostream &os, bool encoded)
187  : my_os(os),
188    my_indent(0),
189    my_encoded(encoded)
190{
191}
192
193void RTTIDisplay::display(Node const *n)
194{
195  if (n) const_cast<Node *>(n)->accept(this);
196  else my_os << "nil";
197  my_os.put('\n');
198}
199
200void RTTIDisplay::visit(Atom *a)
201{
202  newline();
203  my_os << demangle(typeid(*a).name()) << ": ";
204  char const *p = a->position();
205  size_t n = a->length();
206
207  if(n < 1) return;
208  else if(n == 1 && *p == '@')
209  {
210    my_os << "\\@";
211    return;
212  }
213
214  my_os << *p++;
215  while(--n > 0) my_os << *p++;
216}
217
218void RTTIDisplay::visit(List *l) 
219{
220  newline();
221  my_os << demangle(typeid(*l).name()) << ": ";
222  if (my_encoded)
223  {
224    Encoding type = l->encoded_type();
225    if(!type.empty())
226    {
227      my_os << "type=" << type << ' ';
228    }
229    Encoding name = l->encoded_name();
230    if(!name.empty())
231    {
232      my_os << "name=" << name;
233    }
234  }
235  ++my_indent;
236  Node *rest = l;
237  while(rest != 0)
238  {
239    if(rest->is_atom())
240    {
241      rest->accept(this);
242      rest = 0;
243    }
244    else
245    {
246      Node *head = rest->car();
247      if(head == 0)
248      {
249	newline();
250	my_os << "nil";
251      }
252      else
253      {
254	head->accept(this);
255      }
256      rest = rest->cdr();
257    }
258  }
259  --my_indent;
260}
261
262void RTTIDisplay::visit(DupAtom *a)
263{
264  newline();
265  my_os << demangle(typeid(*a).name()) << ": ";
266  char const *pos = a->position();
267  size_t length = a->length();
268
269  if(length == 1 && *pos == '@')
270  {
271    my_os << "\\@";
272    return;
273  }
274
275  my_os << '`';
276  for(size_t i = 0; i < length; ++i) my_os << pos[i];
277  my_os << '`';
278}
279
280void RTTIDisplay::newline()
281{
282  my_os.put('\n');
283  for(size_t i = 0; i != my_indent; ++i) my_os.put(' ');
284}
285
286DotFileGenerator::DotFileGenerator(std::ostream &os) : my_os(os) {}
287void DotFileGenerator::write(PTree::Node const *ptree)
288{
289  my_os << "digraph PTree\n{\n"
290	<< "node[fillcolor=\"#ffffcc\", pencolor=\"#424242\" style=\"filled\"];\n";
291  const_cast<Node *>(ptree)->accept(this);
292  my_os << '}' << std::endl;
293}
294
295void DotFileGenerator::visit(PTree::Atom *a)
296{
297  my_os << (long)a 
298	<< " [label=\"" << std::string(a->position(), a->length())
299	<< "\" fillcolor=\"#ffcccc\"];\n";
300}
301
302void DotFileGenerator::visit(PTree::List *l)
303{
304  my_os << (long)l 
305	<< " [label=\"" << demangle(typeid(*l).name()) << "\"];\n";
306  if (l->car())
307  {
308    l->car()->accept(this);
309    my_os << (long)l << "->" 
310	  << (long)l->car() << ';' << std::endl;
311  }
312  if (l->cdr())
313  {
314    l->cdr()->accept(this);
315    my_os << (long)l << "->" 
316	  << (long)l->cdr() << ';' << std::endl;
317  }
318}
319