Synopsis - Cross-Reference

File: /Synopsis/Parsers/C/ASGTranslator.cc
  1//
  2// Copyright (C) 2005 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 "ASGTranslator.hh"
  9#include <Synopsis/Trace.hh>
 10#include <Synopsis/PTree/Writer.hh> // for PTree::reify
 11#include <Support/Path.hh>
 12
 13using namespace Synopsis;
 14
 15namespace
 16{
 17  ScopedName sname(std::string const &name) { return ScopedName(name);}
 18
 19class UnknownSymbol : public std::runtime_error
 20{
 21public:
 22  explicit UnknownSymbol(std::string const &n)
 23    : std::runtime_error("Unknown symbol: " + n) {}
 24};
 25
 26}
 27#define qname(arg) qname_(Python::Tuple(arg))
 28
 29ASGTranslator::ASGTranslator(std::string const &filename,
 30			     std::string const &base_path, bool primary_file_only,
 31			     Synopsis::IR ir, bool v, bool d)
 32  : asg_kit_("C"),
 33    sf_kit_("C"),
 34    declarations_(ir.declarations()),
 35    types_(ir.types()),
 36    files_(ir.files()),
 37    raw_filename_(filename),
 38    base_path_(base_path),
 39    primary_file_only_(primary_file_only),
 40    lineno_(0),
 41    verbose_(v),
 42    debug_(d),
 43    buffer_(0),
 44    declaration_(0),
 45    defines_class_or_enum_(false)
 46{
 47  Trace trace("ASGTranslator::ASGTranslator", Trace::TRANSLATION);
 48
 49  Python::Module qn = Python::Module::import("Synopsis.QualifiedName");
 50  qname_ = qn.attr("QualifiedCxxName");
 51
 52  // determine canonical filenames
 53  Path path = Path(raw_filename_).abs();
 54  std::string long_filename = path.str();
 55  path.strip(base_path_);
 56  std::string short_filename = path.str();
 57
 58  SourceFile file = files_.get(short_filename);
 59  if (file)
 60    file_ = file;
 61  else
 62  {
 63    file_ = sf_kit_.create_source_file(short_filename, long_filename);
 64    files_.set(short_filename, file_);
 65  }
 66  file_.set_primary(true);
 67
 68  Python::Object define = types_.attr("__setitem__");
 69  types_.set(qname(sname("char")), asg_kit_.create_builtin_type_id(sname("char")));
 70  types_.set(qname(sname("short")), asg_kit_.create_builtin_type_id(sname("short")));
 71  types_.set(qname(sname("int")), asg_kit_.create_builtin_type_id(sname("int")));
 72  types_.set(qname(sname("long")), asg_kit_.create_builtin_type_id(sname("long")));
 73  types_.set(qname(sname("unsigned")), asg_kit_.create_builtin_type_id(sname("unsigned")));
 74  types_.set(qname(sname("unsigned long")), asg_kit_.create_builtin_type_id(sname("unsigned long")));
 75  types_.set(qname(sname("float")), asg_kit_.create_builtin_type_id(sname("float")));
 76  types_.set(qname(sname("double")), asg_kit_.create_builtin_type_id(sname("double")));
 77  types_.set(qname(sname("void")), asg_kit_.create_builtin_type_id(sname("void")));
 78  types_.set(qname(sname("...")), asg_kit_.create_builtin_type_id(sname("...")));
 79  types_.set(qname(sname("long long")), asg_kit_.create_builtin_type_id(sname("long long")));
 80  types_.set(qname(sname("long double")), asg_kit_.create_builtin_type_id(sname("long double")));
 81  // some GCC extensions...
 82  types_.set(qname(sname("__builtin_va_list")), asg_kit_.create_builtin_type_id(sname("__builtin_va_list")));
 83}
 84
 85void ASGTranslator::translate(PTree::Node *ptree, Buffer &buffer)
 86{
 87  Trace trace("ASGTranslator::translate", Trace::TRANSLATION);
 88  buffer_ = &buffer;
 89  ptree->accept(this);
 90}
 91
 92void ASGTranslator::visit(PTree::List *node)
 93{
 94  if (node->car()) node->car()->accept(this);
 95  if (node->cdr()) node->cdr()->accept(this);
 96}
 97
 98void ASGTranslator::visit(PTree::Declarator *declarator)
 99{
100  Trace trace("ASGTranslator::visit(PTree::Declarator *)", Trace::TRANSLATION);
101  trace << declarator;
102  if (!declaration_ || !PTree::first(declarator)) return; // empty
103
104  bool visible = update_position(declarator);
105  PTree::Encoding name = declarator->encoded_name();
106  PTree::Encoding type = declarator->encoded_type();
107  if (type.is_function())
108  {
109    trace << "declare function " << name << " (" << type << ')' 
110	  << raw_filename_ << ':' << lineno_;
111
112    ASG::TypeIdList parameter_types;
113    ASG::TypeId return_type = lookup_function_types(type, parameter_types);
114    ASG::Function::Parameters parameters;
115    PTree::Node *p = PTree::rest(declarator);
116    while (p && p->car() && *p->car() != '(') p = PTree::rest(p);
117    translate_parameters(PTree::second(p), parameter_types, parameters);
118
119    size_t length = (name.front() - 0x80);
120    ScopedName sname(std::string(name.begin() + 1, name.begin() + 1 + length));
121    ASG::Modifiers pre;
122    ASG::Modifiers post;
123    ASG::Function function = asg_kit_.create_function(file_, lineno_,
124                                                      "function",
125                                                      pre,
126                                                      return_type,
127                                                      post,
128                                                      sname,
129                                                      sname.get(0));
130    function.parameters().extend(parameters);
131    if (declaration_) add_comments(function, declaration_->get_comments());
132    add_comments(function, declarator->get_comments());
133    if (visible) declare(function);
134  }
135  else
136  {
137    ASG::TypeId t = lookup(type);
138    size_t length = (name.front() - 0x80);
139    ScopedName sname;
140    if (scope_.size()) sname = scope_.top().name();
141    sname.append(std::string(name.begin() + 1, name.begin() + 1 + length));
142
143    std::string vtype;
144    if (scope_.size())
145    {
146      vtype = scope_.top().type();
147      if (vtype == "class" || vtype == "struct" || vtype == "union")
148        vtype = "data member";
149      else if (vtype == "function")
150	vtype = "local variable";
151    }
152    else
153      vtype += "variable";
154    ASG::Variable variable = asg_kit_.create_variable(file_, lineno_,
155                                                      vtype, sname, t, false);
156    if (declaration_) add_comments(variable, declaration_->get_comments());
157    add_comments(variable, declarator->get_comments());
158    if (visible) declare(variable);
159  }
160}
161
162void ASGTranslator::visit(PTree::Declaration *declaration)
163{
164  Trace trace("ASGTranslator::visit(PTree::Declaration *)", Trace::TRANSLATION);
165  // Cache the declaration while traversing the individual declarators;
166  // the comments are passed through.
167  declaration_ = declaration;
168  visit(static_cast<PTree::List *>(declaration));
169  declaration_ = 0;
170}
171
172void ASGTranslator::visit(PTree::FunctionDefinition *def)
173{
174  Trace trace("ASGTranslator::visit(PTree::FunctionDefinition *)", Trace::TRANSLATION);
175  // Cache the declaration while traversing the individual declarators;
176  // the comments are passed through.
177  declaration_ = def;
178  // Only traverse declaration-specifier-seq and declarator, but not body
179  if (PTree::first(def)) PTree::first(def)->accept(this);
180  PTree::second(def)->accept(this);
181  declaration_ = 0;
182}
183
184void ASGTranslator::visit(PTree::ClassSpec *class_spec)
185{
186  Trace trace("ASGTranslator::visit(PTree::ClassSpec *)", Trace::TRANSLATION);
187  
188  bool visible = update_position(class_spec);
189
190  size_t size = PTree::length(class_spec);
191  if (size == 2) // forward declaration ?
192  {
193    // [ class|struct <name> ]
194    PTree::Encoding t = class_spec->encoded_name();
195    try 
196    {
197      ASG::TypeId tt = lookup(t);
198      // The type is known, thus nothing to do. Move on.
199      return;
200    }
201    catch (UnknownSymbol const &e) {}
202    std::string type = PTree::reify(PTree::first(class_spec));
203    std::string name = PTree::reify(PTree::second(class_spec));
204    ScopedName sname(name);
205
206    ASG::Forward forward = asg_kit_.create_forward(file_, lineno_,
207                                                   type, sname);
208    add_comments(forward, class_spec->get_comments());
209    if (visible)
210    {
211      declare(forward);
212      declare_type(sname, forward);
213    }
214    else
215      declare_type(sname);
216      
217    defines_class_or_enum_ = true;
218    return;
219  }
220
221  std::string type = PTree::reify(PTree::first(class_spec));
222  std::string name;
223  PTree::ClassBody *body = 0;
224
225  if (size == 4) // struct definition
226  {
227    // [ class|struct <name> <inheritance> [{ body }] ]
228
229    name = PTree::reify(PTree::second(class_spec));
230    body = static_cast<PTree::ClassBody *>(PTree::nth(class_spec, 3));
231  }
232  else if (size == 3) // anonymous struct definition
233  {
234    // [ struct [nil nil] [{ ... }] ]
235
236    PTree::Encoding ename = class_spec->encoded_name();
237    size_t length = (ename.front() - 0x80);
238    name = std::string(ename.begin() + 1, ename.begin() + 1 + length);
239    body = static_cast<PTree::ClassBody *>(PTree::nth(class_spec, 2));
240  }
241
242  ScopedName sname(name);
243  ASG::Class class_ = asg_kit_.create_class(file_, lineno_, type, sname);
244  add_comments(class_, class_spec->get_comments());
245  if (visible)
246  {
247    declare(class_);
248    declare_type(sname, class_);
249  }
250  else
251    declare_type(sname);
252
253  scope_.push(class_);
254  defines_class_or_enum_ = false;
255  body->accept(this);
256  scope_.pop();
257  defines_class_or_enum_ = true;
258}
259
260void ASGTranslator::visit(PTree::EnumSpec *enum_spec)
261{
262  Trace trace("ASGTranslator::visit(PTree::EnumSpec *)", Trace::TRANSLATION);
263
264  bool visible = update_position(enum_spec);
265  std::string name;
266  
267  if (!PTree::second(enum_spec)) //anonymous
268  {
269    PTree::Encoding ename = enum_spec->encoded_name();
270    size_t length = (ename.front() - 0x80);
271    name = std::string(ename.begin() + 1, ename.begin() + 1 + length);
272  }
273  else
274    name = PTree::reify(PTree::second(enum_spec));
275
276  ASG::Enumerators enumerators;
277  PTree::Node *enode = PTree::second(PTree::third(enum_spec));
278
279  PTree::Encoding t = enum_spec->encoded_name();
280  try 
281  {
282    ASG::TypeId tt = lookup(t);
283    // The type is known. If we find a body, this is a parse error:
284//     if (enode)
285//       throw std::runtime_error("redefinition of 'enum " + name + "'");
286
287    // Else it may be an elaborate specifier, or a forward declaration.
288    // Nothing to do. Move on.
289    return;
290  }
291  catch (UnknownSymbol const &e) {}
292
293
294
295
296
297  ASG::Enumerator enumerator;
298  while (enode)
299  {
300    // quite a costly way to update the line number...
301    update_position(enode);
302    PTree::Node *penumor = PTree::first(enode);
303    if (penumor->is_atom())
304    {
305      // Just a name
306      ScopedName sname(PTree::reify(penumor));
307      enumerator = asg_kit_.create_enumerator(file_, lineno_, sname, "");
308      add_comments(enumerator, static_cast<PTree::CommentedAtom *>(penumor)->get_comments());
309    }
310    else
311    {
312      // Name = Value
313      ScopedName sname(PTree::reify(PTree::first(penumor)));
314      std::string value;
315      if (PTree::length(penumor) == 3)
316        value = PTree::reify(PTree::third(penumor));
317      enumerator = asg_kit_.create_enumerator(file_, lineno_, sname, value);
318      add_comments(enumerator, static_cast<PTree::CommentedAtom *>(penumor)->get_comments());
319    }
320    enumerators.append(enumerator);
321    enode = PTree::rest(enode);
322    // Skip comma
323    if (enode && enode->car() && *enode->car() == ',') enode = PTree::rest(enode);
324  }
325  // Add a dummy enumerator at the end to absorb trailing comments.
326  PTree::Node *close = PTree::third(PTree::third(enum_spec));
327  ASG::Builtin eos = asg_kit_.create_builtin(file_, lineno_,
328                                             "EOS", sname(std::string("EOS")));
329  add_comments(eos, static_cast<PTree::CommentedAtom *>(close));
330  enumerators.append(eos);
331  
332  // Create ASG.Enum object
333  ASG::Enum enum_ = asg_kit_.create_enum(file_, lineno_, name, enumerators);
334  add_comments(enum_, enum_spec);
335
336  if (visible)
337  {
338    declare(enum_);
339    declare_type(ScopedName(name), enum_);
340  }
341  else
342    declare_type(ScopedName(name));
343
344  defines_class_or_enum_ = true;
345}
346
347void ASGTranslator::visit(PTree::Typedef *typed)
348{
349  Trace trace("ASGTranslator::visit(PTree::Typedef *)", Trace::TRANSLATION);
350  defines_class_or_enum_ = false;
351
352  bool visible = update_position(typed);
353
354  // the second child node may be an inlined class spec, i.e.
355  // typedef struct {...} type;
356  PTree::second(typed)->accept(this);
357  for (PTree::Node *d = PTree::third(typed); d; d = PTree::tail(d, 2))
358  {
359    if(PTree::type_of(d->car()) != Token::ntDeclarator)  // is this check necessary
360      continue;
361    
362    PTree::Declarator *declarator = static_cast<PTree::Declarator *>(d->car());
363    PTree::Encoding name = declarator->encoded_name();
364    PTree::Encoding type = declarator->encoded_type();
365    trace << "declare type " << name << " (" << type << ')' 
366	  << raw_filename_ << ':' << lineno_;
367    assert(name.is_simple_name());
368    size_t length = (name.front() - 0x80);
369    ScopedName sname(std::string(name.begin() + 1, name.begin() + 1 + length));
370    ASG::TypeId alias = lookup(type);
371    ASG::Declaration declaration = asg_kit_.create_typedef(file_, lineno_,
372                                                           "typedef",
373                                                           sname,
374                                                           alias, defines_class_or_enum_);
375    add_comments(declaration, declarator->get_comments());
376    if (visible)
377    {
378      declare(declaration);
379      declare_type(sname, declaration);
380    }
381    else
382      declare_type(sname);
383  }
384  defines_class_or_enum_ = false;
385}
386
387void ASGTranslator::translate_parameters(PTree::Node *node,
388					 ASG::TypeIdList types,
389					 ASG::Function::Parameters &parameters)
390{
391  Trace trace("ASGTranslator::translate_parameters", Trace::TRANSLATION);
392  if (PTree::length(node) == 1 && *node->car() == "void") return;
393  while (node)
394  {
395    // A parameter has a type, possibly a name and possibly a value.
396    // Treat the value as a string, i.e. don't analyse the expression further.
397    std::string name, value;
398    ASG::Modifiers premods, postmods;
399    if (*node->car() == ',')
400      node = node->cdr();
401    PTree::Node *parameter = PTree::first(node);
402
403    ASG::TypeId type = types.get(0);
404    types.del(0); // pop one value
405    if (PTree::length(parameter) == 3)
406    {
407      PTree::Declarator *decl = static_cast<PTree::Declarator*>(PTree::nth(parameter, 2));
408      name = PTree::reify(decl->name());
409      value = PTree::reify(decl->initializer());
410
411      // Skip keywords (eg: register) which are Leaves
412      PTree::Node *atom = PTree::nth(parameter, 0);
413      if (atom) premods.append(PTree::reify(atom));
414    }
415    ASG::Parameter p = asg_kit_.create_parameter(premods, type, postmods,
416                                                 name, value);
417    parameters.append(p);
418    node = PTree::rest(node);
419  }
420}
421
422void ASGTranslator::add_comments(ASG::Declaration declarator, PTree::Node *c)
423{
424  Trace trace("ASGTranslator::add_comments", Trace::TRANSLATION);
425  if (!declarator || !c) return;
426  
427  Python::List comments;
428
429  // Loop over all comments in the list
430  // If the last comment is separated from the declaration by more than a single '\n',
431  // we add a None to the list.
432  bool suspect = false;
433  for (PTree::Node *next = PTree::rest(c); c && !c->is_atom(); next = PTree::rest(c))
434  {
435    PTree::Node *first = PTree::first(c);
436    if (!first || !first->is_atom())
437    {
438      c = next;
439      continue;
440    }
441    // Check if comment is continued, eg: consecutive C++ comments
442    while (next && PTree::first(next) && PTree::first(next)->is_atom())
443    {
444      if (!strncmp(first->position() + first->length() - 2, "*/", 2))
445        break;
446      if (strncmp(PTree::first(next)->position(), "//", 2))
447        break;
448      char const *next_pos = PTree::first(next)->position();
449      char const *start_pos = PTree::first(c)->position();
450      char const *curr_pos = start_pos + PTree::first(c)->length();
451      // Must only be whitespace between current comment and next
452      // and only one newline
453      int newlines = 0;
454      while (curr_pos < next_pos && strchr(" \t\r\n", *curr_pos))
455        if (*curr_pos == '\n' && newlines > 0)
456          break;
457        else if (*curr_pos++ == '\n')
458          ++newlines;
459      if (curr_pos < next_pos)
460        break;
461      // Current comment stretches to end of next
462      int len = int(next_pos - start_pos + PTree::first(next)->length());
463      c->set_car(first = new PTree::Atom(start_pos, len));
464      // Skip the combined comment
465      next = PTree::rest(next);
466    }
467    suspect = false;
468    char const *pos = first->position() + first->length();
469    while (*pos && strchr(" \t\r", *pos)) ++pos;
470    if (*pos == '\n')
471    {
472      ++pos;
473      // Found only allowed \n
474      while (*pos && strchr(" \t\r", *pos)) ++pos;
475      if (*pos == '\n' || !strncmp(pos, "/*", 2)) suspect = true;
476    }
477    Python::Object comment = PTree::reify(first);
478    comments.append(comment);
479
480//     if (links_) links_->long_span(first, "file-comment");
481    // Set first to 0 so we dont accidentally do them twice (eg:
482    // when parsing expressions)
483    c->set_car(0);
484    c = next;
485  }
486  if (suspect) comments.append(Python::Object());
487  declarator.annotations().set("comments", comments);
488}
489
490bool ASGTranslator::update_position(PTree::Node *node)
491{
492  Trace trace("ASGTranslator::update_position", Trace::TRANSLATION);
493
494  std::string filename;
495  lineno_ = buffer_->origin(node->begin(), filename);
496
497  if (filename != raw_filename_)
498  {
499    if (primary_file_only_)
500      // raw_filename_ remains the primary file's name
501      // and all declarations from elsewhere are ignored
502      return false;
503    raw_filename_ = filename;
504
505    // determine canonical filenames
506    Path path = Path(filename).abs();
507    std::string long_filename = path.str();
508    path.strip(base_path_);
509    std::string short_filename = path.str();
510
511    SourceFile file = files_.get(short_filename);
512    if (file)
513      file_ = file;
514    else
515    {
516      file_ = sf_kit_.create_source_file(short_filename, long_filename);
517      files_.set(short_filename, file_);
518    }
519  }
520  return true;
521}
522
523ASG::TypeId ASGTranslator::lookup(PTree::Encoding const &name)
524{
525  Trace trace("ASGTranslator::lookup", Trace::SYMBOLLOOKUP);
526  trace << name;
527  name_ = name;
528  ASG::TypeId type;
529  decode_type(name.begin(), type);
530  return type;
531}
532
533ASG::TypeId ASGTranslator::lookup_function_types(PTree::Encoding const &name,
534                                                 ASG::TypeIdList &parameters)
535{
536  Trace trace("ASGTranslator::lookup_function_types", Trace::SYMBOLLOOKUP);
537  trace << name;
538  name_ = name;
539
540  PTree::Encoding::iterator i = name.begin();
541  assert(*i == 'F');
542  ++i;
543  while (true)
544  {
545    ASG::TypeId parameter;
546    i = decode_type(i, parameter);
547    if (parameter)
548      parameters.append(parameter);
549    else
550      break;
551  }
552  ++i; // skip over '_'
553  ASG::TypeId return_type;
554  i = decode_type(i, return_type);
555  return return_type;
556}
557
558void ASGTranslator::declare(ASG::Declaration declaration)
559{
560  if (scope_.size())
561    scope_.top().declarations().append(declaration);
562  else
563    declarations_.append(declaration);    
564  file_.declarations().append(declaration);
565}
566
567ASG::TypeId ASGTranslator::declare_type(ScopedName name,
568                                        ASG::Declaration declaration)
569{
570  Trace trace("ASGTranslator::declare_type", Trace::SYMBOLLOOKUP);
571  trace << name;
572  ASG::TypeId type = asg_kit_.create_declared_type_id(name, declaration);
573  types_.set(qname(name), type);
574  return type;
575}
576
577ASG::TypeId ASGTranslator::declare_type(ScopedName name)
578{
579  Trace trace("ASGTranslator::declare_type(unknown)", Trace::SYMBOLLOOKUP);
580  trace << name;
581  ASG::TypeId type = asg_kit_.create_unknown_type_id(name);
582  types_.set(qname(name), type);
583  return type;
584}
585
586// This is almost a verbatim copy of the Decoder::decode
587// methods from Synopsis/Parsers/Cxx/syn/decoder.cc
588// with some minor modifications to disable the C++ specific things.
589// FIXME: this ought to be part of SymbolLookup::Type.
590PTree::Encoding::iterator ASGTranslator::decode_name(PTree::Encoding::iterator i,
591                                                     std::string &name)
592{
593  Trace trace("ASGTranslator::decode_name", Trace::PARSING);
594  size_t length = *i++ - 0x80;
595  name = std::string(length, '\0');
596  std::copy(i, i + length, name.begin());
597  i += length;
598  return i;
599}
600
601PTree::Encoding::iterator ASGTranslator::decode_type(PTree::Encoding::iterator i,
602                                                     ASG::TypeId &type)
603{
604  Trace trace("ASGTranslator::decode_type", Trace::PARSING);
605  ASG::Modifiers premod, postmod;
606  std::string name;
607  ASG::TypeId base;
608
609  // Loop forever until broken
610  while (i != name_.end() && !name.length() && !base)
611  {
612    int c = *i++;
613    switch (c)
614    {
615      case 'P':
616	postmod.insert(0, "*");
617	break;
618//       case 'R':
619// 	postmod.insert(0, "&");
620// 	break;
621      case 'S':
622	premod.append("signed");
623	break;
624      case 'U':
625	premod.append("unsigned");
626	break;
627      case 'C':
628	premod.append("const");
629	break;
630      case 'V':
631	premod.append("volatile");
632	break;
633      case 'A':
634      {
635	std::string array("[");
636	while (*i != '_') array.push_back(*i++);
637	array.push_back(']');
638	++i;
639	postmod.append(array);
640	  break;
641      }
642//       case '*':
643//       {
644// 	ScopedName n;
645// 	n.push_back("*");
646// 	base = new Types::Dependent(n);
647// 	break;
648//       }
649      case 'i':
650	name = "int";
651	break;
652      case 'v':
653	name = "void";
654	break;
655//       case 'b':
656// 	name = "bool";
657// 	break;
658      case 's':
659	name = "short";
660	break;
661      case 'c':
662	name = "char";
663	break;
664//       case 'w':
665// 	name = "wchar_t";
666// 	break;
667      case 'l':
668	name = "long";
669	break;
670      case 'j':
671	name = "long long";
672	break;
673      case 'f':
674	name = "float";
675	break;
676      case 'd':
677	name = "double";
678	break;
679      case 'r':
680	name = "long double";
681	break;
682      case 'e':
683	name = "...";
684	break;
685      case '?':
686	name = "int"; // in C, no return type spec defaults to int
687	break;
688//       case 'Q':
689// 	base = decodeQualType();
690// 	break;
691      case '_':
692	--i;
693	type = ASG::TypeId();
694	return i; // end of func params
695      case 'F':
696	i = decode_func_ptr(i, base, postmod);
697	break;
698//       case 'T':
699// 	base = decodeTemplate();
700// 	break;
701//       case 'M':
702// 	// Pointer to member. Format is same as for named types
703// 	name = decodeName() + "::*";
704// 	break;
705      default:
706	if (c > 0x80)
707	{
708	  --i;
709	  i = decode_name(i, name);
710	  break;
711	}
712	// FIXME
713	// 	    std::cerr << "\nUnknown char decoding '"<<m_string<<"': "
714	// 		 << char(c) << " " << c << " at "
715	// 		 << (m_iter - m_string.begin()) << std::endl;
716    } // switch
717  } // while
718  if (!base && !name.length())
719  {
720    // FIXME
721    // 	std::cerr << "no type or name found decoding " << m_string << std::endl;
722    type = ASG::TypeId();
723    return i;
724  }
725  if (!base)
726  {
727    base = types_.get(qname(sname(name)));
728    if (!base) throw UnknownSymbol(name);
729  }
730  if (premod.empty() && postmod.empty())
731    type = base;
732  else
733    type = asg_kit_.create_modifier_type_id(base, premod, postmod);
734
735  return i;
736}
737
738PTree::Encoding::iterator ASGTranslator::decode_func_ptr(PTree::Encoding::iterator i,
739                                                         ASG::TypeId &type,
740                                                         ASG::Modifiers &postmod)
741{
742  Trace trace("ASGTranslator::decode_func_ptr", Trace::PARSING);
743  // Function ptr. Encoded same as function
744  ASG::Modifiers premod;
745  // Move * from postmod to funcptr's premod. This makes the output be
746  // "void (*convert)()" instead of "void (convert)()*"
747  if (postmod.size() > 0 && postmod.get(0) == "*")
748  {
749    premod.append(postmod.get(0));
750    postmod.erase(postmod.begin());
751  }
752  ASG::TypeIdList parameters;
753  while (true)
754  {
755    ASG::TypeId parameter;
756    i = decode_type(i, parameter);
757    if (parameter)
758      parameters.append(parameter);
759    else
760      break;
761  }
762  ++i; // skip over '_'
763  i = decode_type(i, type);
764  type = asg_kit_.create_function_type_id(type, premod, parameters);
765  return i;
766}