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 }
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
227
228
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
375
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,