Synopsis - Cross-Reference

File: src/Synopsis/PTree/Encoding.cc
  1//
  2// Copyright (C) 1997 Shigeru Chiba
  3// Copyright (C) 2004 Stefan Seefeld
  4// All rights reserved.
  5// Licensed to the public under the terms of the GNU LGPL (>= 2),
  6// see the file COPYING for details.
  7//
  8
  9#include <Synopsis/Trace.hh>
 10#include <Synopsis/PTree/Node.hh>
 11#include <Synopsis/PTree/Atoms.hh>
 12#include <Synopsis/PTree/TypeVisitor.hh>
 13#include <Synopsis/PTree/Encoding.hh>
 14#include <Synopsis/Lexer.hh>
 15#include <iostream>
 16#include <sstream>
 17
 18using namespace Synopsis;
 19using namespace PTree;
 20
 21Node *Encoding::bool_t = 0;
 22Node *Encoding::char_t = 0;
 23Node *Encoding::wchar_t_t = 0;
 24Node *Encoding::int_t = 0;
 25Node *Encoding::short_t = 0;
 26Node *Encoding::long_t = 0;
 27Node *Encoding::float_t = 0;
 28Node *Encoding::double_t = 0;
 29Node *Encoding::void_t = 0;
 30
 31Node *Encoding::signed_t = 0;
 32Node *Encoding::unsigned_t = 0;
 33Node *Encoding::const_t = 0;
 34Node *Encoding::volatile_t = 0;
 35
 36Node *Encoding::operator_name = 0;
 37Node *Encoding::new_operator = 0;
 38Node *Encoding::anew_operator = 0;
 39Node *Encoding::delete_operator = 0;
 40Node *Encoding::adelete_operator = 0;
 41
 42Node *Encoding::star = 0;
 43Node *Encoding::ampersand = 0;
 44Node *Encoding::comma = 0;
 45Node *Encoding::dots = 0;
 46Node *Encoding::scope = 0;
 47Node *Encoding::tilder = 0;
 48Node *Encoding::left_paren = 0;
 49Node *Encoding::right_paren = 0;
 50Node *Encoding::left_bracket = 0;
 51Node *Encoding::right_bracket = 0;
 52Node *Encoding::left_angle = 0;
 53Node *Encoding::right_angle = 0;
 54
 55namespace
 56{
 57class Unmangler
 58{
 59public:
 60  typedef Encoding::iterator iterator;
 61
 62  Unmangler(iterator begin, iterator end) : my_cursor(begin), my_end(end) {}
 63
 64  std::string unmangle();
 65  std::string unmangle_name();
 66  std::string unmangle_qname();
 67  std::string unmangle_template();
 68  std::string unmangle_func(std::string&);
 69
 70private:
 71  iterator my_cursor;
 72  iterator const my_end;
 73};
 74
 75std::string Unmangler::unmangle_name()
 76{
 77  Trace trace("Unmangler::unmangle_name()", Trace::PTREE);
 78  size_t length = *my_cursor++ - 0x80;
 79  std::string name(length, '\0');
 80  std::copy(my_cursor, my_cursor + length, name.begin());
 81  my_cursor += length;
 82  return name;
 83}
 84
 85std::string Unmangler::unmangle()
 86{
 87  Trace trace("Unmangler::unmangle()", Trace::PTREE);
 88  std::string premod, postmod;
 89  std::string name;
 90  std::string base;
 91  
 92  while (my_cursor != my_end && !name.length() && !base.length())
 93  {
 94    int c = *my_cursor++;
 95    switch (c)
 96    {
 97      case 'P':
 98	postmod += "*";
 99	break;
100      case 'R':
101	postmod += "&";
102	break;
103      case 'S':
104	premod += "signed ";
105	break;
106      case 'U':
107	premod += "unsigned ";
108	break;
109      case 'C':
110	premod += "const ";
111	break;
112      case 'V':
113	premod += "volatile ";
114	break;
115      case 'A':
116      {
117	std::string array("[");
118	while (*my_cursor != '_') array += *my_cursor++;
119	array += ']';
120	++my_cursor;
121	postmod += array;
122	break;
123      }
124      case '*':
125	base = "*";
126	break;
127      case 'i':
128	name = "int";
129	break;
130      case 'v':
131	name = "void";
132	break;
133      case 'b':
134	name = "bool";
135	break;
136      case 's':
137	name = "short";
138	break;
139      case 'c':
140	name = "char";
141	break;
142      case 'w':
143	name = "wchar_t";
144	break;
145      case 'l':
146	name = "long";
147	break;
148      case 'j':
149	name = "long long";
150	break;
151      case 'f':
152	name = "float";
153	break;
154      case 'd':
155	name = "double";
156	break;
157      case 'r':
158	name = "long double";
159	break;
160      case 'e':
161	name = "...";
162	break;
163      case '?':
164	return ""; //FIXME !
165      case 'Q':
166	base = unmangle_qname();
167	break;
168      case '_':
169	--my_cursor;
170	return ""; // end of func params
171      case 'F':
172	base = unmangle_func(postmod);
173	break;
174      case 'T':
175	base = unmangle_template();
176	break;
177      case 'M':
178	// Pointer to member. Format is same as for named types
179	name = unmangle_name() + "::*";
180	break;
181      default:
182	assert(c > 0x80);
183	--my_cursor;
184	name = unmangle_name();
185	break;
186    } // switch
187  } // while
188  if (!base.length() && !name.length())
189    throw std::runtime_error("unmangling error");
190  if (!base.length())
191    base = name;
192  return premod + base + postmod;
193}
194
195std::string Unmangler::unmangle_qname()
196{
197  Trace trace("Unmangler::unmangle_qname()", Trace::PTREE);
198  // Qualified type: first is num of scopes (at least one), each a name.
199  std::string qname;
200  int scopes = *my_cursor++ - 0x80;
201  while (scopes--)
202  {
203    std::string name;
204    // Only handle two things here: names and templates
205    if (*my_cursor >= 0x80)
206      name = unmangle_name();
207    else if (*my_cursor == 'T')
208    {
209      ++my_cursor;
210      name = unmangle_name();
211      name += '<';
212      iterator tend = my_cursor;
213      tend += *my_cursor++ - 0x80;
214      bool first = true;
215      while (my_cursor <= tend)
216      {
217	if (!first) name += ',';
218	else first = false;
219	name += unmangle();
220      }
221      name += '>';
222    }
223    else
224    {
225      
226      //std::cerr << "Warning: Unknown type inside Q: " << *my_cursor << std::endl;
227      // FIXME
228      //std::cerr << "         Decoding " << my_string << std::endl;
229    }
230    if (qname.length()) qname += "::" + name;
231    else qname = name;
232  }
233  return qname;
234}
235
236std::string Unmangler::unmangle_func(std::string& postmod)
237{
238  Trace trace("Unmangler::unmangle_func()", Trace::PTREE);
239  // Function ptr. Encoded same as function
240  std::string premod;
241  // Move * from postmod to funcptr's premod. This makes the output be
242  // "void (*convert)()" instead of "void (convert)()*"
243  if (postmod.size() > 0 && postmod[0] == '*')
244  {
245    premod += postmod[0];
246    postmod.erase(postmod.begin());
247  }
248  std::vector<std::string> params;
249  while (true)
250  {
251    std::string type = unmangle();
252    if (type.empty())
253      break;
254    else
255      params.push_back(type);
256  }
257  ++my_cursor; // skip over '_'
258  std::string returnType = unmangle();
259  std::string ret = returnType + "(*)(";
260  if (params.size()) ret += params[0];
261  for (size_t p = 1; p != params.size(); ++p)
262    ret += "," + params[p];
263  ret += ")";
264  return ret;
265}
266
267std::string Unmangler::unmangle_template()
268{
269  Trace trace("Unmangler::unmangle_template()", Trace::PTREE);
270
271  // Template type: Name first, then size of arg field, then arg
272  // types eg: T6vector54cell <-- 5 is len of 4cell
273  if (*my_cursor == 'T')
274    ++my_cursor;
275  std::string name = unmangle_name();
276  iterator tend = my_cursor;
277  tend += *my_cursor++ - 0x80;
278  name += "<";
279  if (my_cursor <= tend) name += unmangle();
280  while (my_cursor <= tend) name += "," + unmangle();
281  name += ">";
282  return name;
283}
284
285}
286
287
288void Encoding::do_init_static()
289{
290  Encoding::bool_t = new PTree::Kwd::Bool("bool", 4);
291  Encoding::char_t = new PTree::Kwd::Char("char", 4);
292  Encoding::wchar_t_t = new PTree::Kwd::WChar("wchar_t", 7);
293  Encoding::int_t = new PTree::Kwd::Int("int", 3);
294  Encoding::short_t = new PTree::Kwd::Short("short", 5);
295  Encoding::long_t = new PTree::Kwd::Long("long", 4);
296  Encoding::float_t = new PTree::Kwd::Float("float", 5);
297  Encoding::double_t = new PTree::Kwd::Double("double", 6);
298  Encoding::void_t = new PTree::Kwd::Void("void", 4);
299
300  Encoding::signed_t = new PTree::Kwd::Signed("signed", 6);
301  Encoding::unsigned_t = new PTree::Kwd::Unsigned("unsigned", 8);
302  Encoding::const_t = new PTree::Kwd::Const("const", 5);
303  Encoding::volatile_t = new PTree::Kwd::Volatile("volatile", 8);
304  
305  Encoding::operator_name = new PTree::Kwd::Operator("operator", 8);
306  Encoding::new_operator = new PTree::Kwd::New("new", 3);
307  Encoding::anew_operator = new PTree::Kwd::New("new[]", 5);
308  Encoding::delete_operator = new PTree::Kwd::Delete("delete", 6);
309  Encoding::adelete_operator = new PTree::Kwd::Delete("delete[]", 8);
310  
311  Encoding::star = new PTree::Atom("*", 1);
312  Encoding::ampersand = new PTree::Atom("&", 1);
313  Encoding::comma = new PTree::Atom(",", 1);
314  Encoding::dots = new PTree::Atom("...", 3);
315  Encoding::scope = new PTree::Atom("::", 2);
316  Encoding::tilder = new PTree::Atom("~", 1);
317  Encoding::left_paren = new PTree::Atom("(", 1);
318  Encoding::right_paren = new PTree::Atom(")", 1);
319  Encoding::left_bracket = new PTree::Atom("[", 1);
320  Encoding::right_bracket = new PTree::Atom("]", 1);
321  Encoding::left_angle = new PTree::Atom("<", 1);
322  Encoding::right_angle = new PTree::Atom(">", 1);
323}
324
325Encoding Encoding::simple_name(PTree::Atom const *name)
326{
327  Encoding retn;
328  retn.append_with_length(name->position(), name->length());
329  return retn;
330}
331
332const char *Encoding::copy() const
333{
334  return strcpy(new (GC) char[my_buffer.size() + 1], (const char *)my_buffer.c_str());
335}
336
337void Encoding::cv_qualify(const PTree::Node *cv1, const PTree::Node *cv2)
338{
339  bool c = false, v = false;
340  if(cv1 && !cv1->is_atom())
341    while(cv1)
342    {
343      int kind = PTree::type_of(cv1->car());
344      cv1 = cv1->cdr();
345      if(kind == Token::CONST) c = true;
346      else if(kind == Token::VOLATILE) v = true;
347    }
348
349  if(cv2 && !cv2->is_atom())
350    while(cv2)
351    {
352      int kind = PTree::type_of(cv2->car());
353      cv2 = cv2->cdr();
354      if(kind == Token::CONST) c = true;
355      else if(kind == Token::VOLATILE) v = true;
356    }
357
358  if(v) prepend('V');
359  if(c) prepend('C');
360}
361
362void Encoding::global_scope()
363{
364  append(0x80);
365}
366
367// simple_name() is also used for operator names
368
369void Encoding::simple_name(const PTree::Node *id)
370{
371  append_with_length(id->position(), id->length());
372}
373
374// anonymous() generates an internal name for anonymous enum and class
375// declarations.
376
377void Encoding::anonymous()
378{
379  static int i = 0;
380  static char name[] = "`0000";
381  int n = i++;
382  name[1] = n / 1000 + '0';
383  name[2] = (n / 100) % 10 + '0';
384  name[3] = (n / 10) % 10 + '0';
385  name[4] = n % 10 + '0';
386  append_with_length(name, 5);
387}
388
389void Encoding::template_(const PTree::Node *name, const Encoding &args)
390{
391  append('T');
392  simple_name(name);
393  append_with_length(args);
394}
395
396void Encoding::qualified(int n)
397{
398  prepend(0x80 + n);
399  prepend('Q');
400}
401
402void Encoding::destructor(const PTree::Node *class_name)
403{
404  size_t len = class_name->length();
405  append((unsigned char)(0x80 + len + 1));
406  append('~');
407  append(class_name->position(), len);
408}
409
410void Encoding::ptr_operator(int t)
411{
412  if(t == '*') prepend('P');
413  else prepend('R');
414}
415
416void Encoding::ptr_to_member(const Encoding &enc, int n)
417{
418  prepend(enc);
419  if(n >= 2)
420  {
421    prepend((unsigned char)(0x80 + n));
422    prepend('Q');
423  }
424  prepend('M');
425}
426
427void Encoding::cast_operator(const Encoding &type)
428{
429  append((unsigned char)(0x80 + type.size() + 1));
430  append('@');
431  append(type);
432}
433
434void Encoding::array(unsigned long s) 
435{
436  std::ostringstream oss;
437  oss << 'A' << s << '_';
438  std::string str = oss.str();
439  prepend(str.c_str(), str.size());
440}
441
442Encoding::iterator Encoding::end_of_scope() const
443{
444  if (!is_qualified()) return end(); // no scope
445  
446  iterator i = begin() + 2;                 // skip 'Q' and <size>
447  if (*i >= 0x80) return i + *i - 0x80 + 1; // simple name
448  if (*i == 'T')                            // template
449  {
450    i += *(i+1) - 0x80 + 2;                 // skip 'T' and simple name
451    i += *i - 0x80 + 1;                     // skip template parameters
452    return i;
453  }
454  // never get here
455  std::ostringstream oss;
456  oss << "internal error in qualified name encoding " << my_buffer;
457  throw std::domain_error(oss.str());
458}
459
460Encoding Encoding::get_scope() const
461{
462  if (!is_qualified()) return "";    // no scope
463  return Encoding(begin() + 2, end_of_scope());
464}
465
466Encoding Encoding::get_symbol() const
467{
468  if (!is_qualified()) return *this; // no scope
469  iterator i = ++begin();
470  size_t size = static_cast<size_t>(*i - 0x80);
471  Encoding retn(end_of_scope(), end());
472  if (size > 2) retn.qualified(size - 1);
473  return retn;
474}
475
476std::string Encoding::unmangled() const
477{
478  if (empty()) return "";
479  Unmangler unmangler(begin(), end());
480  return unmangler.unmangle();
481}
482
483Encoding Encoding::get_template_arguments() const
484{
485  int m = my_buffer[0] - 0x80;
486  size_t length = my_buffer[1] - 0x80;
487  if(m <= 0)
488  {
489    return Encoding(my_buffer.begin() + 2, my_buffer.begin() + 2 + length);
490  }
491  else
492  {
493    return Encoding(my_buffer.begin() + 2 + m, my_buffer.begin() + 2 + m + length);
494  }
495}
496
497PTree::Node *Encoding::make_name()
498{
499  PTree::Node *name;
500  int len = my_buffer[0] - 0x80;
501  if(len > 0)
502    name = new PTree::Identifier((const char*)&*(my_buffer.begin() + 1), len);
503  else name = 0;
504  my_buffer.erase(my_buffer.begin(), my_buffer.begin() + len + 1);
505  return name;
506}
507
508PTree::Node *Encoding::make_qname()
509{
510  int n = my_buffer[0] - 0x80;
511  PTree::Node *qname = 0;
512  while(n-- > 0)
513  {
514    PTree::Node *name = make_name();
515    if(name) qname = snoc(qname, name);
516    if(n > 0) qname = snoc(qname, scope);
517  }
518  return qname;
519}
520
521PTree::Node *Encoding::make_ptree(PTree::Node *decl)
522{
523  PTree::Node *cv;
524  PTree::Node *typespec = 0;
525  if(decl) decl = PTree::list(decl);
526  while(true)
527  {
528    cv = 0;
529    unsigned char code = pop();
530    switch(code)
531    {
532      case 'b' :
533	typespec = PTree::snoc(typespec, bool_t);
534	return PTree::list(typespec, decl);
535      case 'c' :
536	typespec = PTree::snoc(typespec, char_t);
537	return PTree::list(typespec, decl);
538      case 'w' :
539	typespec = PTree::snoc(typespec, wchar_t_t);
540	return PTree::list(typespec, decl);
541      case 'i' :
542	typespec = PTree::snoc(typespec, int_t);
543	return PTree::list(typespec, decl);
544      case 's' :
545	typespec = PTree::snoc(typespec, short_t);
546	return PTree::list(typespec, decl);
547      case 'l' :
548	typespec = PTree::snoc(typespec, long_t);
549	return PTree::list(typespec, decl);
550	break;
551      case 'j' :
552	typespec = PTree::nconc(typespec, PTree::list(long_t, long_t));
553	return PTree::list(typespec, decl);
554	break;
555      case 'f' :
556	typespec = PTree::snoc(typespec, float_t);
557	return PTree::list(typespec, decl);
558	break;
559      case 'd' :
560	typespec = PTree::snoc(typespec, double_t);
561	return PTree::list(typespec, decl);
562	break;
563      case 'r' :
564	typespec = PTree::nconc(typespec, PTree::list(long_t, double_t));
565	return PTree::list(typespec, decl);
566      case 'v' :
567	typespec = PTree::snoc(typespec, void_t);
568	return PTree::list(typespec, decl);
569      case 'e' :
570	return dots;
571      case '?' :
572	return PTree::list(typespec, decl);
573      case 'Q' :
574	typespec = PTree::snoc(typespec, make_qname());
575	return PTree::list(typespec, decl);
576      case 'S' :
577	typespec = PTree::snoc(typespec, signed_t);
578	break;
579      case 'U' :
580	typespec = PTree::snoc(typespec, unsigned_t);
581	break;
582      case 'C' :
583	if(my_buffer[0] == 'V')
584	{
585	  pop();
586	  cv = PTree::list(const_t, volatile_t);
587	}
588	else cv = PTree::list(const_t);
589	goto const_or_volatile;
590      case 'V' :
591	cv = PTree::list(volatile_t);
592      const_or_volatile :
593	switch(my_buffer[0])
594	{
595	  case 'M' :
596	  case 'P' :
597	  case 'R' :
598	    decl = PTree::nconc(cv, decl);
599	    break;
600	  case 'F' :
601	    pop();
602	    goto cv_function;
603	  default :
604	    typespec = PTree::nconc(cv, typespec);
605	    break;
606	}
607	break;
608      case 'M' :
609        {
610	  PTree::Node *ptr;
611	  if(my_buffer[0] == 'Q')
612	  {
613	    pop();
614	    ptr = make_qname();
615	  }
616	  else ptr = make_name();
617	  
618	  ptr = PTree::list(ptr, scope, star);
619	  decl = PTree::cons(ptr, decl);
620	}
621	goto pointer_or_reference;
622      case 'P' :
623	decl = PTree::cons(star, decl);
624	goto pointer_or_reference;
625      case 'R' :
626	decl = PTree::cons(ampersand, decl);
627      pointer_or_reference :
628	if(my_buffer[0] == 'A' || my_buffer[0] == 'F')
629	  decl = PTree::list(PTree::list(left_paren, decl, right_paren));
630	break;
631      case 'A' :
632      {
633	char c = 'A';
634	do
635	{
636	  c = front();
637	  pop();
638	} while (c != '_');
639	// FIXME: need to put the actual dimension into the generated tree.
640	decl = PTree::nconc(decl, PTree::list(left_bracket,
641					      right_bracket));
642	break;
643      }
644      case 'F' :
645      cv_function :
646        {
647	  PTree::Node *args = 0;
648	  while(my_buffer[0] != '\0')
649	  {
650	    if(my_buffer[0] == '_')
651	    {
652	      pop();
653	      break;
654	    }
655	    else if(my_buffer[0] == 'v')
656	    {
657	      pop(2);
658	      break;
659	    }
660	    if(args != 0) args = PTree::snoc(args, comma);
661	    args = PTree::snoc(args, make_ptree(0));
662	  }
663	  decl = PTree::nconc(decl, PTree::list(left_paren, args, right_paren));
664	  if(cv) decl = PTree::nconc(decl, cv);
665	}
666	break;
667      case '\0' :
668	return PTree::list(typespec, decl);
669      case 'T' :
670	{
671	  PTree::Node *tlabel = make_name();      
672	  PTree::Node *args = 0;
673	  int n = pop() - 0x80;
674	  const unsigned char *stop = &*my_buffer.begin() + n;
675	  while(&*my_buffer.begin() < stop)
676	  {
677	    if(args) args = PTree::snoc(args, comma);
678	    args = PTree::snoc(args, make_ptree(0));
679	  }
680	  tlabel = PTree::list(tlabel, PTree::list(left_angle, args, right_angle));
681	  typespec = PTree::nconc(typespec, tlabel);
682	  return PTree::list(typespec, decl);
683	}
684      case '*' :
685	goto error;
686      default :
687	prepend(code); // 'unget'
688	if(code >= 0x80)
689	{
690	  if(typespec == 0) typespec = make_name();
691	  else typespec = PTree::snoc(typespec, make_name());
692	  return PTree::list(typespec, decl);
693	}
694      error :
695	throw std::runtime_error("Encoding::make_ptree(): sorry, cannot handle this type");
696	break;
697    }
698  }
699}
700
701PTree::Node *Encoding::name_to_ptree()
702{
703  if(my_buffer.empty()) return 0;
704  if(my_buffer == (const unsigned char *)"new[]")
705    return PTree::list(operator_name,