Synopsis - Cross-Reference

File: /Synopsis/Parsers/Cxx/Walker.cc
   1//
   2// Copyright (C) 2000 Stefan Seefeld
   3// Copyright (C) 2000 Stephen Davies
   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 <Python.h>
  10#include <iostream>
  11#include <string>
  12#include <typeinfo>
  13#include <sstream>
  14#include <algorithm>
  15
  16#include <Synopsis/Buffer.hh>
  17#include <Synopsis/PTree.hh>
  18#include <Synopsis/PTree/Writer.hh>
  19#include <Synopsis/PTree/Display.hh>
  20
  21#include "Walker.hh"
  22#include "STrace.hh"
  23#include "Types.hh"
  24#include "ASG.hh"
  25#include "Builder.hh"
  26#include "Decoder.hh"
  27#include "TypeIdFormatter.hh"
  28#include "SXRGenerator.hh"
  29#include "Lookup.hh"
  30#include "Filter.hh"
  31#include "Dictionary.hh"
  32
  33using namespace ASG;
  34using Synopsis::Token;
  35using Synopsis::Buffer;
  36#ifdef DO_TRACE
  37int STrace::slevel = 0, STrace::dlevel = 0;
  38std::ostringstream* STrace::stream = 0;
  39STrace::string_list STrace::m_list;
  40std::ostream& STrace::operator <<(PTree::Node *p)
  41{
  42  std::ostream& out = operator <<("-");
  43  PTree::display(p, out, true);
  44  return out;
  45}
  46#endif
  47
  48namespace
  49{
  50//. Helper function to recursively find the first left-most leaf node
  51PTree::Node *find_left_leaf(PTree::Node *node, PTree::Node *& parent)
  52{
  53  if (!node || node->is_atom()) return node;
  54  // Non-leaf node. So find first leafy child
  55  PTree::Node *leaf;
  56  while (node)
  57  {
  58    if (node->car())
  59    {
  60      // There is a child here..
  61      if (node->car()->is_atom())
  62      {
  63        // And this child is a leaf! return it and set parent
  64        parent = node;
  65        return node->car();
  66      }
  67      if ((leaf = find_left_leaf(node->car(), parent)))
  68        // Not a leaf so try recursing on it
  69        return leaf;
  70    }
  71    // No leaves from car of this node, so try next cdr
  72    node = node->cdr();
  73  }
  74  return 0;
  75}
  76
  77PTree::Node *strip_cv_from_integral_type(PTree::Node *integral)
  78{
  79  if(integral == 0) return 0;
  80
  81  if(!integral->is_atom())
  82    if(PTree::is_a(integral->car(), Token::CONST, Token::VOLATILE))
  83      return PTree::second(integral);
  84    else if(PTree::is_a(PTree::second(integral), Token::CONST, Token::VOLATILE))
  85      return integral->car();
  86
  87  return integral;
  88}
  89
  90PTree::Node *get_class_or_enum_spec(PTree::Node *typespec)
  91{
  92  PTree::Node *spec = strip_cv_from_integral_type(typespec);
  93  if(PTree::is_a(spec, Token::ntClassSpec, Token::ntEnumSpec))
  94    return spec;
  95  return 0;
  96}
  97
  98PTree::ClassSpec *get_class_template_spec(PTree::Node *body)
  99{
 100  if(*PTree::third(body) == ';')
 101  {
 102    PTree::Node *spec = strip_cv_from_integral_type(PTree::second(body));
 103    return static_cast<PTree::ClassSpec *>(spec);
 104  }
 105  return 0;
 106}
 107
 108}
 109
 110
 111
 112Walker *Walker::g_walker = 0;
 113
 114Walker::Walker(FileFilter* filter, Builder* builder, Buffer* buffer)
 115  : //Walker(buffer),
 116    my_builder(builder),
 117    my_filter(filter),
 118    my_buffer(buffer),
 119    my_decoder(new Decoder(my_builder)),
 120    my_declaration(0),
 121    my_in_typedef(false),
 122    my_defines_class_or_enum(false),
 123    my_template(0),
 124    my_lineno(0),
 125    my_file(0),
 126    sxr_(0),
 127    my_store_decl(false),
 128    my_type_formatter(new TypeIdFormatter()),
 129    my_function(0),
 130    my_type(0),
 131    my_scope(0),
 132    my_postfix_flag(Postfix_Var),
 133    my_in_template_decl(false)
 134{
 135  g_walker = this; // FIXME: is this needed?
 136  my_builder->set_walker(this);
 137  my_lookup = my_builder->lookup();
 138}
 139
 140// Destructor
 141Walker::~Walker()
 142{
 143  delete my_decoder;
 144  delete my_type_formatter;
 145}
 146
 147// The name returned is just the node's text if the node is a leaf. Otherwise,
 148// the ToString method of Ptree is used, which is rather expensive since it
 149// creates a temporary write buffer and reifies the node tree into it.
 150std::string
 151Walker::parse_name(PTree::Node *node) const
 152{
 153  return PTree::reify(node);
 154}
 155
 156void
 157Walker::set_store_links(SXRGenerator* sxr)
 158{
 159  sxr_ = sxr;
 160}
 161
 162int Walker::line_of_ptree(PTree::Node *node)
 163{
 164  update_line_number(node);
 165  return my_lineno;
 166}
 167
 168// Updates the line number stored in this Walker instance, and the filename
 169// stored in the Builder instance at my_builder. The filename is only set if
 170// the actual char* changed (which only happens when the preprocessor places
 171// another #line directive)
 172void Walker::update_line_number(PTree::Node *ptree)
 173{
 174  // Ask the Parser for the linenumber of the ptree. This used to be
 175  // expensive until I hacked buffer.cc to cache the last line number found.
 176  // Now it's okay as long as you are looking for lines sequentially.
 177  std::string filename;
 178  my_lineno = my_buffer->origin(ptree->begin(), filename);
 179  if (filename != my_filename)
 180  {
 181    my_filename = filename;
 182    my_file = my_filter->get_sourcefile(my_filename.c_str());
 183    my_builder->set_file(my_file);
 184  }
 185}
 186
 187ASG::Comment *
 188make_Comment(SourceFile* file, int line, PTree::Node *first, bool suspect=false)
 189{
 190  return new ASG::Comment(file, line, PTree::reify(first), suspect);
 191}
 192
 193PTree::Atom *make_Leaf(const char *pos, size_t len)
 194{
 195    return new PTree::Atom(pos, len);
 196}
 197
 198// Adds the given comments to the given declaration.
 199void
 200Walker::add_comments(ASG::Declaration* decl, PTree::Node *node)
 201{
 202  if (!node) return;
 203  std::vector<std::string> comments;
 204
 205  // First, make sure that node is a list of comments
 206  if (PTree::type_of(node) == Token::ntDeclaration)
 207    node = static_cast<PTree::Declaration*>(node)->get_comments();
 208  // Loop over all comments in the list
 209  bool suspect = false;
 210  for (PTree::Node *next = PTree::rest(node); node && !node->is_atom(); next = PTree::rest(node))
 211  {
 212    PTree::Node *first = PTree::first(node);
 213    if (!first || !first->is_atom())
 214    {
 215      node = next;
 216      continue;
 217    }
 218    // Check if comment is continued, eg: consecutive C++ comments
 219    while (next && PTree::first(next) && PTree::first(next)->is_atom())
 220    {
 221      if (!strncmp(first->position() + first->length() - 2, "*/", 2))
 222        break;
 223      if (strncmp(PTree::first(next)->position(), "//", 2))
 224        break;
 225      const char *next_pos = PTree::first(next)->position();
 226      const char *start_pos = PTree::first(node)->position();
 227      const char *curr_pos = start_pos + PTree::first(node)->length();
 228      // Must only be whitespace between current comment and next
 229      // and only one newline
 230      int newlines = 0;
 231      while (curr_pos < next_pos && strchr(" \t\r\n", *curr_pos))
 232        if (*curr_pos == '\n' && newlines > 0)
 233          break;
 234        else if (*curr_pos++ == '\n')
 235          ++newlines;
 236      if (curr_pos < next_pos)
 237        break;
 238      // Current comment stretches to end of next
 239      int len = int(next_pos - start_pos + PTree::first(next)->length());
 240      //node->SetCar(first = new Leaf(start_pos, len));
 241      node->set_car(first = make_Leaf(start_pos, len));
 242      // Skip the combined comment
 243      next = PTree::rest(next);
 244    }
 245
 246    // all comments that are not immediately (i.e. separated
 247    // by a single new line) followed by a declaration are
 248    // marked as 'suspect'
 249    suspect = false;
 250    const char *pos = first->position() + first->length();
 251    while (*pos && strchr(" \t\r", *pos)) ++pos;
 252    if (*pos == '\n')
 253    {
 254      ++pos;
 255      // Found only allowed \n
 256      while (*pos && strchr(" \t\r", *pos)) ++pos;
 257      if (*pos == '\n' || !strncmp(pos, "/*", 2)) suspect = true;
 258    }
 259
 260    if (decl)
 261      comments.push_back(PTree::reify(first));
 262    if (sxr_) sxr_->long_span(first, "comment");
 263    // Set first to 0 so we dont accidentally do them twice (eg:
 264    // when parsing expressions)
 265    node->set_car(0);
 266    node = next;
 267  }
 268  if (suspect) comments.push_back("");
 269  // Now add the comments, if applicable
 270  if (decl)
 271    decl->comments() = comments;
 272}
 273
 274// -- These methods implement add_comments for various node types that store
 275// comment pointers
 276void Walker::add_comments(ASG::Declaration* decl, PTree::CommentedAtom *node)
 277{
 278  if (node) add_comments(decl, node->get_comments());
 279}
 280void Walker::add_comments(ASG::Declaration* decl, PTree::Declaration* node)
 281{
 282  if (node) add_comments(decl, node->get_comments());
 283}
 284void Walker::add_comments(ASG::Declaration* decl, PTree::Declarator* node)
 285{
 286  if (node) add_comments(decl, node->get_comments());
 287}
 288void Walker::add_comments(ASG::Declaration* decl, PTree::NamespaceSpec* node)
 289{
 290  if (node) add_comments(decl, node->get_comments());
 291}
 292void Walker::find_comments(PTree::Node *node)
 293{
 294  PTree::Node *parent;
 295  PTree::Node *leaf = find_left_leaf(node, parent);
 296  if (leaf) add_comments(0, dynamic_cast<PTree::CommentedAtom *>(leaf));
 297}
 298
 299PTree::Node *Walker::translate_arg_decl_list(bool, PTree::Node *, PTree::Node *)
 300{
 301  STrace trace("Walker::translate_arg_decl_list NYI");
 302  return 0;
 303}
 304
 305PTree::Node *Walker::translate_initialize_args(PTree::Declarator*, PTree::Node *)
 306{
 307  STrace trace("Walker::translate_initialize_args NYI");
 308  return 0;
 309}
 310
 311PTree::Node *Walker::translate_assign_initializer(PTree::Declarator*, PTree::Node *)
 312{
 313  STrace trace("Walker::translate_assign_initializer NYI");
 314  return 0;
 315}
 316
 317// Format the given parameters. my_type_formatter is used to format the given
 318// list of parameters into a string, suitable for use as the name of a
 319// Function object.
 320std::string Walker::format_parameters(ASG::Parameter::vector& params)
 321{
 322  // TODO: Tell formatter to expand typedefs! Eg: this function uses a typedef
 323  // in implementation, but not for declaration in the class!!!!!!
 324  ASG::Parameter::vector::iterator iter = params.begin(), end = params.end();
 325  if (iter == end) return "()";
 326  // Set scope for formatter
 327  ASG::Scope* scope = my_builder->scope();
 328  if (scope) my_type_formatter->push_scope(scope->name());
 329  else my_type_formatter->push_scope(ScopedName());
 330  // Format the parameters one at a time
 331  std::ostringstream buf;
 332  buf << "(" << my_type_formatter->format((*iter++)->type());
 333  while (iter != end)
 334    buf << "," << my_type_formatter->format((*iter++)->type());
 335  buf << ")";
 336  my_type_formatter->pop_scope();
 337  return buf.str();
 338}
 339
 340void
 341Walker::translate(PTree::Node *node)
 342{
 343  STrace trace("Walker::translate");
 344  try
 345  {
 346    if (node) node->accept(this);
 347  }
 348  catch (Dictionary::KeyError const &e)
 349  {
 350    std::cerr << "Unknown type '" << e.name << "'\n";
 351    std::string filename;
 352    unsigned long line = my_buffer->origin(node->begin(), filename);
 353    std::cerr << " (" << filename << ":" << line << ")" << std::endl;
 354    throw;    
 355  }
 356  catch (Dictionary::MultipleError const &e)
 357  {
 358    std::cerr << "Multiple definitions found for type '" << e.name << "'\n";
 359    for (Dictionary::Type_vector::const_iterator i = e.types.begin(); i != e.types.end(); ++i)
 360      std::cerr << (*i)->name() << std::endl;
 361    throw;    
 362  }
 363  // Debug and non-debug modes handle these very differently
 364#ifdef DEBUG
 365  catch (const TranslateError& e)
 366  {
 367    if (e.node) node = e.node;
 368    std::string filename;
 369    unsigned long line = my_buffer->origin(node->begin(),
 370					   filename);
 371    LOG("Warning: An exception occurred:" << " (" << filename << ":" << line << ")");
 372    LOG("- " << e.str());
 373  }
 374  catch (const std::exception& e)
 375  {
 376    LOG("Warning: An exception occurred: " << e.what());
 377    nodeLOG(node);
 378  }
 379  catch (...)
 380  {
 381    LOG("Warning: An exception occurred (unknown) at:");
 382    nodeLOG(node);
 383  }
 384#else
 385  catch (const TranslateError& e)
 386  {
 387      // This error usually means that the syntax highlighting failed, and
 388      // can be safely ignored
 389  }
 390  catch (const std::exception& e)
 391  {
 392    std::cerr << "Warning: An exception occurred: " << e.what() << std::endl;
 393    std::cerr << "At: ";
 394    std::string filename;
 395    unsigned long line = my_buffer->origin(node->begin(), filename);
 396    std::cerr << " (" << filename << ":" << line << ")" << std::endl;
 397    throw;
 398  }
 399  catch (...)
 400  {
 401    std::cerr << "Warning: An unknown exception occurred: " << std::endl;
 402    std::cerr << "At: ";
 403    std::string filename;
 404    unsigned long line = my_buffer->origin(node->begin(), filename);
 405    std::cerr << " (" << filename << ":" << line << ")" << std::endl;
 406    throw;
 407  }
 408#endif
 409}
 410
 411// Default translate, usually means a literal
 412void Walker::visit(PTree::Atom *node)
 413{
 414  STrace trace("Walker::visit(PTree::Atom *)");
 415  // Determine type of node
 416  std::string s = PTree::reify(node);
 417  const char *str = s.c_str();
 418  if ((*str >= '0' && *str <= '9') || *str == '.')
 419  {
 420    // Assume whole node is a number
 421    if (sxr_) sxr_->span(node, "literal");
 422    // TODO: decide if Long, Float, Double, etc
 423    const char* num_type = (*str == '.' ? "double" : "int");
 424    while (*++str)
 425    {
 426      if (*str >= '0' && *str <= '9') {}
 427      else if (*str == 'e' || *str == 'E')
 428      {
 429        // Might be followed by + or -
 430        ++str;
 431        if (*str == '+' || *str == '-') ++str;
 432      }
 433      else if (*str == '.') num_type = "double";
 434      else if (*str == 'f' || *str == 'F')
 435      {
 436        num_type = "float";
 437        break;
 438      }
 439      else if (*str == 'l' || *str == 'L')
 440      {
 441        if (strcmp(num_type, "int") == 0) num_type = "long";
 442        else if (strcmp(num_type, "long") == 0) num_type = "long long";
 443	else if (strcmp(num_type, "unsigned") == 0) num_type = "unsigned long";
 444	else if (strcmp(num_type, "float") == 0) num_type = "long double";
 445	else if (strcmp(num_type, "double") == 0) num_type = "long double";
 446        else
 447          std::cerr << "Unknown num type: " << num_type << std::endl;
 448      }
 449      else if (*str == 'u' || *str == 'U')
 450      {
 451        if (strcmp(num_type, "int") == 0) num_type = "unsigned";
 452        else if (strcmp(num_type, "long") == 0) num_type = "unsigned long";
 453        else
 454          std::cerr << "Unknown num type: " << num_type << std::endl;
 455      }
 456      else break;// End of numeric constant
 457    }
 458    my_type = my_lookup->lookupType(num_type);
 459  }
 460  else if (*str == '\'')
 461  {
 462    // Whole node is a char literal
 463    if (sxr_) sxr_->span(node, "string");
 464    my_type = my_lookup->lookupType("char");
 465  }
 466  else if (*str == '"')
 467  {
 468    // Assume whole node is a string
 469    if (sxr_) sxr_->span(node, "string");
 470    my_type = my_lookup->lookupType("char");
 471    Types::Type::Mods pre, post;
 472    pre.push_back("const");
 473    post.push_back("*");
 474    my_type = new Types::Modifier(my_type, pre, post);
 475  }
 476  else if (*str == '/' && !node->is_atom())
 477  {
 478    // Assume comment. Must be a list of comments!
 479    ASG::Declaration* decl;
 480    update_line_number(node);
 481    decl = my_builder->add_tail_comment(my_lineno);
 482    add_comments(decl, static_cast<PTree::CommentedAtom *>(node));
 483  }
 484  else
 485  {
 486#ifdef DEBUG
 487    STrace trace("Walker::TranslatePtree");
 488    LOG("Warning: Unknown Ptree "<<PTree::type_of(node));
 489    nodeLOG(node);
 490    //*((char*)0) = 1; // force breakpoint, or core dump :)
 491#endif
 492  }
 493}
 494
 495// As various nodes may through due to incomplete symbol
 496// lookup support, we need an 'exception firewall' here to
 497// be able to traverse the following nodes
 498void Walker::visit(PTree::List *node)
 499{
 500  for (PTree::Node *i = node; i; i = i->cdr())
 501    if (i->car())
 502      try { i->car()->accept(this);}
 503      catch (const TranslateError &) {}
 504}
 505
 506void Walker::visit(PTree::CommentedAtom *node)
 507{
 508  // The only purpose of this method is to filter
 509  // out those atoms that are used as end markers.
 510  // They can be recognized by having length() == 0.
 511  if (node->length() == 0)
 512  {
 513    // The begin of the node coincides with the start of the comment.
 514    update_line_number(node);
 515    ASG::Builtin *builtin = my_builder->add_tail_comment(my_lineno);
 516    add_comments(builtin, node);
 517  }
 518  else
 519    visit(static_cast<PTree::Atom *>(node));
 520}
 521
 522//. NamespaceSpec
 523void Walker::visit(PTree::NamespaceSpec *node)
 524{
 525  STrace trace("Walker::visit(PTree::NamespaceSpec *)");
 526  update_line_number(node);
 527
 528  PTree::Node *key = PTree::first(node);
 529  PTree::Node *id = PTree::second(node);
 530  PTree::Node *body = PTree::third(node);
 531  
 532  if (sxr_) sxr_->span(key, "keyword");
 533
 534  // Start the namespace
 535  ASG::Namespace* ns;
 536  if (id)
 537  {
 538    ns = my_builder->start_namespace(parse_name(id), NamespaceNamed);
 539    ns->set_file(my_file);
 540  }
 541  else ns = my_builder->start_namespace(my_file->name(), NamespaceAnon);
 542
 543  add_comments(ns, static_cast<PTree::NamespaceSpec*>(node));
 544  if (sxr_ && PTree::first(id)) sxr_->xref(id, ns);
 545
 546  // Translate the body
 547  translate(body);
 548
 549  // End the namespace
 550  my_builder->end_namespace();
 551}
 552
 553//. [ : (public|private|protected|0) <name> {, ...} ]
 554std::vector<Inheritance*> Walker::translate_inheritance_spec(PTree::Node *node)
 555{
 556  STrace trace("Walker::translate_inheritance_spec");
 557  std::vector<Inheritance*> ispec;
 558  Types::Type *type;
 559  while (node)
 560  {
 561    node = node->cdr(); // skip : or ,
 562    // the attributes
 563    std::vector<std::string> attributes(PTree::length(node->car()) - 1);
 564    for (int i = 0; i != PTree::length(node->car()) - 1; ++i)
 565    {
 566      attributes[i] = parse_name(PTree::nth(node->car(), i));
 567      if (sxr_) sxr_->span(PTree::nth(node->car(), i), "keyword");
 568    }
 569    // look up the parent type
 570    PTree::Node *name = PTree::last(node->car())->car();
 571    if (name->is_atom())
 572    {
 573      try
 574      {
 575        type = my_lookup->lookupType(parse_name(name));
 576      }
 577      catch (const TranslateError)
 578      {
 579        // Ignore error, and put an Unknown in, instead
 580        ScopedName uname;
 581        uname.push_back(parse_name(name));
 582        type = new Types::Unknown(uname);
 583      }
 584    }
 585    else
 586    {
 587      my_decoder->init(name->encoded_name());
 588      type = my_decoder->decodeType();
 589    }
 590    if (sxr_) sxr_->xref(name, type);
 591
 592    node = node->cdr();
 593    // add it to the list
 594    ispec.push_back(new ASG::Inheritance(type, attributes));
 595  }
 596  return ispec;
 597}
 598
 599void Walker::visit(PTree::ClassSpec *node)
 600{
 601  // REVISIT: figure out why this method is so long
 602  STrace trace("Walker::visit(PTree::ClassSpec*)");
 603
 604  ASG::Parameter::vector* is_template = my_template;
 605  my_template = 0;
 606  int size = PTree::length(node);
 607  PTree::Node *pClass = PTree::first(node);
 608  PTree::Node *pName = 0, *pInheritance = 0;
 609  PTree::ClassBody *pBody = 0;
 610
 611  if (size == 2)
 612  {
 613    // Forward declaration
 614    // [ class|struct <name> ]
 615    pName = PTree::nth(node, 1);
 616    std::string name = parse_name(pName);
 617    if (is_template)
 618      LOG("Templated class forward declaration " << name);
 619    ASG::Forward *class_ = my_builder->add_forward(my_lineno, name, parse_name(pClass),
 620                                                   is_template);
 621    add_comments(class_, node->get_comments());
 622    return;
 623  }
 624  else if (size == 4)
 625  {
 626    // [ class|struct <name> <inheritance> [{ body }] ]
 627    pName = PTree::nth(node, 1);
 628    pInheritance = PTree::nth(node, 2);
 629    pBody = static_cast<PTree::ClassBody *>(PTree::nth(node, 3));
 630  }
 631  else if (size == 3)
 632    // An anonymous struct. OpenC++ encodes us a unique
 633    // (may be qualified if nested) name
 634    // [ struct [nil nil] [{ ... }] ]
 635    pBody = static_cast<PTree::ClassBody *>(PTree::nth(node, 2));
 636  else
 637    throw nodeERROR(node, "Class node has bad length: " << size);
 638
 639  if (sxr_) sxr_->span(pClass, "keyword");
 640  else update_line_number(node);
 641  // Create ASG.Class object
 642  ASG::Class *clas;
 643  std::string type = parse_name(pClass);
 644  PTree::Encoding enc = node->encoded_name();
 645  my_decoder->init(enc);
 646  if (enc.at(0) == 'T')
 647  {
 648    Types::Parameterized* param = my_decoder->decodeTemplate();
 649    // If a non-type param was found, its name will be '*'
 650    for (size_t i = 0; i < param->parameters().size(); i++)
 651      if (Types::Dependent* dep = dynamic_cast<Types::Dependent*>(param->parameters()[i]))
 652      {
 653        if (dep->name().size() == 1 && dep->name()[0] == "*")
 654        {
 655          // Find the value of this parameter
 656          std::string name = parse_name(PTree::nth(PTree::second(PTree::second(pName)), i*2));
 657          dep->name()[0] = name;
 658        }
 659      }
 660
 661    my_type_formatter->push_scope(my_builder->scope()->name());
 662    std::string name = my_type_formatter->format(param);
 663    my_type_formatter->pop_scope();
 664    std::string primary_name;
 665    if (pName)
 666      primary_name = parse_name(pName->is_atom() ? pName : PTree::first(pName));
 667    clas = my_builder->start_class(my_lineno, type, name, is_template, primary_name);
 668    // TODO: figure out spec stuff, like what to do with vars, link to
 669    // original template, etc.
 670  }
 671  else if (enc.at(0) == 'Q')
 672  {
 673    ScopedName names;
 674    my_decoder->decodeQualName(names);
 675    clas = my_builder->start_class(my_lineno, type, names);
 676  }
 677  else
 678  {
 679    std::string name = my_decoder->decodeName();
 680    std::string primary_name;
 681    if (pName)
 682      primary_name = parse_name(pName->is_atom() ? pName : PTree::first(pName));
 683    if (pName && !pName->is_atom()) primary_name = parse_name(PTree::first(pName));
 684    clas = my_builder->start_class(my_lineno, type, name, is_template, primary_name);
 685  }
 686  if (sxr_ && pName) sxr_->xref(pName, clas);
 687  LOG("Translating class '" << clas->name() << "'");
 688
 689  // Translate the inheritance spec, if present
 690  if (pInheritance)
 691  {
 692    clas->parents() = translate_inheritance_spec(pInheritance);
 693    my_builder->update_class_base_search();
 694  }
 695
 696  add_comments(clas, node->get_comments());
 697
 698  // Push the impl stack for a cache of func impls
 699  my_func_impl_stack.push_back(FuncImplVec());
 700  my_defines_class_or_enum = false;
 701  // Translate the body of the class
 702  bool in_template_decl = my_in_template_decl;
 703  my_in_template_decl = false;
 704  translate(pBody);
 705
 706  // Translate any func impls inlined in the class
 707  FuncImplVec& vec = my_func_impl_stack.back();
 708  FuncImplVec::iterator iter = vec.begin();
 709  while (iter != vec.end()) translate_func_impl_cache(*iter++);
 710  my_func_impl_stack.pop_back();
 711
 712  my_builder->end_class();
 713  my_in_template_decl = in_template_decl;
 714  my_defines_class_or_enum = true;
 715}
 716
 717PTree::TemplateDecl *
 718Walker::translate_class_template(PTree::TemplateDecl *def, PTree::ClassSpec *node)
 719{
 720  STrace trace("Walker::translate_class_template");
 721  ASG::Parameter::vector* old_params = my_template;
 722  update_line_number(def);
 723  my_builder->start_template();
 724  try
 725  {
 726    translate_template_params(PTree::third(def));
 727    visit(node);
 728  }
 729  catch (...)
 730  {
 731    my_builder->end_template();
 732    my_template = old_params;
 733    throw;
 734  }
 735  my_builder->end_template();
 736  my_template = old_params;
 737  return def;
 738}
 739
 740void Walker::translate_template_params(PTree::Node *params)
 741{
 742  STrace trace("Walker::translate_template_params");
 743  my_template = new ASG::Parameter::vector;
 744  ASG::Parameter::vector& templ_params = *my_template;
 745  // Declare some default parameter values - these should not be modified!
 746  std::string name, value;
 747  ASG::Parameter::Mods pre_mods, post_mods;
 748  while (params)
 749  {
 750    PTree::Node *param = PTree::first(params);
 751    if (PTree::is_a(param, Token::ntParameterDecl))
 752      param = PTree::rest(param);
 753    else if (PTree::is_a(PTree::first(param), Token::ntTemplateDecl))
 754      param = PTree::first(param);
 755    nodeLOG(param);
 756    if (*PTree::first(param) == "class" || *PTree::first(param) == "typename")
 757    {
 758      Types::Dependent* dep = 0;
 759      // Ensure that there is an identifier (it is optional!)
 760      if (param->cdr() && PTree::second(param))
 761      {
 762        dep = my_builder->create_dependent(parse_name(PTree::second(param)));
 763        my_builder->add(dep);
 764      }
 765      ASG::Parameter::Mods paramtype;
 766      paramtype.push_back(parse_name(PTree::first(param)));
 767      templ_params.push_back(new ASG::Parameter(paramtype, dep, post_mods, name, value));
 768    }
 769    else if (*PTree::first(param) == "template")
 770    {
 771      // A template template parameter.
 772      Types::Dependent* dep = 0;
 773      if(PTree::nth(param, 5))
 774      {
 775        dep = my_builder->create_dependent(parse_name(PTree::nth(param, 5)));
 776        my_builder->add(dep);
 777      }
 778      ASG::Parameter::Mods paramtype;
 779      std::string type = "template <" + parse_name(PTree::nth(param, 2)) + "> " + parse_name(PTree::nth(param, 4));
 780      paramtype.push_back(type);
 781      templ_params.push_back(new ASG::Parameter(paramtype, dep, post_mods, name, value));
 782      nodeLOG(param);
 783    }
 784    else
 785    {
 786      // This parameter specifies a value or something
 787      // FIXME can do a lot more here..
 788      LOG("non-type template parameter! approximating..");
 789      nodeLOG(param);
 790      PTree::Node *p = PTree::second(param);
 791      while (p && p->car() && p->car()->is_atom() && (*p->car() == '*' || *p->car() == '&'))
 792        p = PTree::rest(p);
 793      std::string name = parse_name(p);
 794      // FIXME: At this point name will contain the initializer, if it
 795      //        was present. Search for '=' and assign everything after
 796      //        that to the value.
 797      std::string::size_type v = name.find('=');
 798      if (v != std::string::npos)
 799      {
 800	value = name.substr(v + 1);
 801	while (value[0] == ' ') value.erase(value.begin());
 802	name = name.substr(0, v - 1);
 803      }
 804      Types::Dependent* dep = my_builder->create_dependent(name);
 805      my_builder->add(dep);
 806      // Figure out the type of the param
 807      my_decoder->init(PTree::second(param)->encoded_type());
 808      Types::Type* param_type = my_decoder->decodeType();
 809      templ_params.push_back(new ASG::Parameter(pre_mods, param_type, post_mods, name, value));
 810    }
 811    // Skip comma
 812    params = PTree::rest(PTree::rest(params));
 813  }
 814  /*
 815    Types::Template* templ = new Types::Template(decl->name(), decl, templ_params);
 816    if (ASG::Class* clas = dynamic_cast<ASG::Class*>(decl))
 817    clas->set_template_type(templ);
 818    else if (ASG::Function* func = dynamic_cast<ASG::Function*>(decl))
 819    func->set_template_type(templ);
 820    std::ostrstream buf;
 821    buf << "template " << decl->type() << std::ends;
 822    decl->set_type(buf.str());
 823  */
 824}
 825
 826PTree::TemplateDecl *
 827Walker::translate_function_template(PTree::TemplateDecl *def, PTree::Node *node)
 828{
 829  STrace trace("Walker::translate_function_template");
 830  nodeLOG(def);
 831  nodeLOG(node);
 832  PTree::Declaration *decl = dynamic_cast<PTree::Declaration *>(node);
 833  if (!decl)
 834  {
 835    LOG("Warning: Unknown node type in template");
 836    nodeLOG(def);
 837    return 0;
 838  }
 839
 840  LOG("Encoded name is: " << node->encoded_name());
 841
 842  ASG::Parameter::vector* old_params = my_template;
 843  update_line_number(def);
 844  my_builder->start_template();
 845  try
 846  {
 847    translate_template_params(PTree::third(def));
 848    visit(decl);
 849  }
 850  catch (...)
 851  {
 852    my_builder->end_template();
 853    my_template = old_params;
 854    throw;
 855  }
 856  my_builder->end_template();
 857  my_template = old_params;
 858  return 0;
 859}
 860
 861//. Linkage Spec
 862void Walker::visit(PTree::LinkageSpec *node)
 863{
 864  STrace trace("Walker::visit(LinkageSpec*)");
 865  translate(PTree::third(node));
 866}
 867
 868//. Block
 869void Walker::visit(PTree::Block *node)
 870{
 871  STrace trace("Walker::visit(PTree::Block *");
 872  PTree::Node *rest = PTree::second(node);
 873  while (rest)
 874  {
 875    translate(rest->car());
 876    rest = rest->cdr();
 877  }
 878  PTree::Node *close = PTree::third(node);
 879  ASG::Declaration *decl;
 880  decl = my_builder->add_tail_comment(my_lineno);
 881  add_comments(decl, dynamic_cast<PTree::CommentedAtom *>(close));
 882}
 883
 884//. Brace
 885void Walker::visit(PTree::Brace *node)
 886{
 887  STrace trace("Walker::visit(PTree::Brace *)");
 888  PTree::Node *rest = PTree::second(node);
 889  while (rest)
 890  {
 891    translate(rest->car());
 892    rest = rest->cdr();
 893  }
 894  PTree::Node *close = PTree::third(node);
 895  ASG::Declaration *decl;
 896  decl = my_builder->add_tail_comment(my_lineno);
 897  add_comments(decl, dynamic_cast<PTree::CommentedAtom *>(close));
 898}
 899
 900//. TemplateDecl
 901void Walker::visit(PTree::TemplateDecl *node)
 902{
 903  STrace trace("Walker::visit(PTree::TemplateDecl*)");
 904  my_in_template_decl = true;
 905  PTree::Node *body = PTree::nth(node, 4);
 906  PTree::ClassSpec *class_spec = get_class_template_spec(body);
 907
 908  // FIXME: We skip the template handling if the template argument list is empty.
 909  //        For classes we can discover it being a specialization since the class name
 910  //        reveals it (a template-id).
 911  //        Not so for functions. Thus, we need to find a way to remember that a given
 912  //        function is a specialization.
 913  if (PTree::third(node))
 914  {
 915    if (class_spec) translate_class_template(node, class_spec);
 916    else translate_function_template(node, body);
 917  }
 918  else // explicit specialization
 919  {
 920    if (class_spec) visit(class_spec);
 921    else visit(static_cast<PTree::Declaration *>(body));
 922  }
 923  my_in_template_decl = false;
 924}
 925
 926//. A typeof(expr) expression evaluates to the type of 'expr'. This is a GNU
 927//. GCC extension!
 928//. Since the OCC parser can't resolve the type properly, we try to do it here
 929//. and modify the type of the declarations to set it
 930PTree::Node *Walker::translate_typeof(PTree::Node *spec, PTree::Node *declarations)
 931{
 932  STrace trace("Walker::translate_typeof");
 933  return 0;
 934  nodeLOG(spec);
 935  PTree::Encoding enc = PTree::third(spec)->encoded_name();
 936  LOG("The name is: " << enc);
 937  LOG("The type is: " << PTree::third(spec)->encoded_type());
 938  // Find the type referred to by the expression
 939  if (!my_decoder->isName(enc))
 940  {
 941    LOG("typeof is not a simple name: ");
 942    nodeLOG(spec);
 943    return 0;
 944  }
 945  std::string name = my_decoder->decodeName(enc);
 946  LOG("name is " << name);
 947  Types::Type* type = my_lookup->lookupType(name, true);
 948  // Find the declaration it refers to
 949  Types::Declared* declared = dynamic_cast<Types::Declared*>(type);
 950  if (!declared) return 0;
 951  LOG("Looked up " << declared->name());
 952  ASG::Declaration* decl = declared->declaration();
 953  if (!decl) return 0;
 954  LOG("Declaration is " << decl->name());
 955  // TODO: make this a visitor and support different things
 956  if (/*ASG::Function* func =*/ dynamic_cast<ASG::Function*>(decl))
 957  {
 958    LOG("decl is a function.");
 959    while (declarations)
 960    {
 961      PTree::Node *declarator = PTree::first(declarations);
 962      declarations = PTree::rest(declarations);
 963      
 964      if (PTree::type_of(declarator) == Token::ntDeclarator)
 965        ((PTree::Declarator*)declarator)->set_encoded_type("PFv_v");
 966      else
 967        LOG("declarator is " << PTree::type_of(declarator));
 968    }
 969  }
 970  else
 971  {
 972    LOG("unknown decl type");
 973  }
 974  nodeLOG(declarations);
 975  return 0;
 976}
 977
 978void Walker::visit(PTree::Declaration *node)
 979{
 980  STrace trace("Walker::visit(PTree::Declaration*)");
 981  update_line_number(node);
 982  // Link any comments added because we are inside a function body
 983  if (sxr_) find_comments(node);
 984  my_declaration = node;
 985  bool in_typedef = my_in_typedef;
 986  my_in_typedef = false;
 987  my_store_decl = true;
 988  PTree::Node *decls = PTree::third(node);
 989
 990  // Typespecifier may be a class {} etc.
 991  translate_type_specifier(PTree::second(node));
 992  // Or it might be a typeof()
 993  if (PTree::second(node) && PTree::type_of(PTree::second(node)) == Token::ntTypeofExpr)
 994    translate_typeof(PTree::second(node), decls);
 995
 996  if (PTree::is_a(decls, Token::ntDeclarator))
 997  {
 998    // A single declarator is probably a function impl, but could also be
 999    // the declarator in an if or switch condition
1000    PTree::Encoding enc = decls->encoded_type();
1001    if (!enc.empty())
1002    {
1003      // A function may be const, skip the C
1004      PTree::Encoding::iterator i = enc.begin();
1005      while (*i == 'C') ++i;
1006      if (*i != 'F')
1007      {
1008        // Not a function
1009        translate_declarator(decls);
1010        my_declaration = 0;
1011        return;
1012      }
1013    }
1014    translate_function_implementation(node);
1015  }
1016  else
1017    // if it is a function prototype or a variable declaration.
1018    if (!decls->is_atom())        // if it is not ";"
1019      translate_declarators(decls);
1020  my_in_typedef = in_typedef;
1021  my_declaration = 0;
1022}
1023
1024PTree::Node *
1025Walker::translate_declarators(PTree::Node *decls)
1026{
1027  STrace trace("Walker::translate_declarators");
1028  PTree::Node *rest = decls, *p;
1029  while (rest != 0)
1030  {
1031    p = rest->car();
1032    if (PTree::is_a(p, Token::ntDeclarator))
1033    {
1034      translate_declarator(p);
1035      my_store_decl = false;
1036    } // if. There is no else..?
1037    rest = rest->cdr();
1038    // Skip comma
1039    if (rest != 0) rest = rest->cdr();
1040  }
1041  return 0;
1042}
1043
1044//. translate_declarator
1045//. Function proto:
1046//.   [ { * | & }* name ( [params] ) ]
1047//. param:
1048//.   [ [types] { [ { * | & }* name ] { = value } } ]
1049PTree::Node *
1050Walker::translate_declarator(PTree::Node *decl)
1051{
1052  // REVISIT: Figure out why this method is so HUGE!
1053  STrace trace("Walker::translate_declarator");
1054  // Insert code from occ.cc here
1055  PTree::Encoding encname = decl->encoded_name();
1056  PTree::Encoding enctype = decl->encoded_type();
1057  if (encname.empty() || enctype.empty())
1058  {
1059    std::cerr << "encname or enctype empty !" << std::endl;
1060    return 0;
1061  }
1062
1063  try
1064  {
1065    // Decide if this is a function or variable
1066    my_decoder->init(enctype);
1067    code_iter& iter = my_decoder->iter();
1068    bool is_const = false;
1069    while (*iter == 'C')
1070    {
1071      ++iter;
1072      is_const = true;
1073    }
1074    if (*iter == 'F')
1075      return translate_function_declarator(decl, is_const);
1076    else
1077      return translate_variable_declarator(decl, is_const);
1078  }
1079  catch (const TranslateError& e)
1080  {
1081    e.set_node(decl);
1082    throw;
1083  }
1084  return 0;
1085}
1086
1087
1088PTree::Node *
1089Walker::translate_function_declarator(PTree::Node *decl, bool is_const)
1090{
1091  STrace trace("Walker::translate_function_declarator");
1092  ASG::Parameter::vector* is_template = my_template;
1093  my_template = 0;
1094
1095  code_iter& iter = my_decoder->iter();
1096  PTree::Encoding encname = decl->encoded_name();
1097  
1098  // This is a function. Skip the 'F'
1099  ++iter;
1100  
1101  // Create parameter objects
1102  PTree::Node *p_params = PTree::rest(decl);
1103  while (p_params && p_params->car() && *p_params->car() != '(')
1104    p_params = PTree::rest(p_params);
1105  if (!p_params)
1106  {
1107    std::string filename;
1108    unsigned long lineno = my_buffer->origin(decl->begin(), filename);
1109    std::cerr << "Warning: error finding params for '" 
1110	      << PTree::reify(decl) 
1111	      << "\' (at " << filename << ':' << lineno << ')' << std::endl;
1112    return 0;
1113  }
1114  std::vector<ASG::Parameter*> params;
1115  translate_parameters(PTree::second(p_params), params);
1116  my_param_cache = params;
1117  
1118  // Figure out the return type:
1119  while (*iter++ != '_') {} // in case of decoding error this is needed
1120  Types::Type* returnType = my_decoder->decodeType();
1121  
1122  // Figure out premodifiers
1123  std::vector<std::string> premod;
1124  PTree::Node *p = PTree::first(my_declaration);
1125  while (p)
1126  {
1127    premod.push_back(PTree::reify(p->car()));
1128    p = PTree::rest(p);
1129  }
1130
1131  ASG::Function* func = 0;
1132  // Find name:
1133  if (encname.at(0) == 'Q')
1134  {
1135    // The name is qualified, which introduces a bit of difficulty
1136    std::vector<std::string> names;
1137    my_decoder->init(encname);
1138    my_decoder->decodeQualName(names);
1139    names.back() += format_parameters(params);
1140    // A qual name must already be declared, so find it:
1141    try
1142    {
1143      Types::Named* named_type = my_lookup->lookupType(names, true);
1144      func = Types::declared_cast<ASG::Function>(named_type);
1145    }
1146    catch (const Types::wrong_type_cast &)
1147    {
1148      throw ERROR("Qualified function name wasn't a function:" << names);
1149    }
1150    // expand param info, since we now have names for them
1151    std::vector<ASG::Parameter*>::iterator piter = func->parameters().begin();
1152    std::vector<ASG::Parameter*>::iterator pend = func->parameters().end();
1153    std::vector<ASG::Parameter*>::iterator new_piter = params.begin();
1154    while (piter != pend)
1155    {
1156      ASG::Parameter* param = *piter++, *new_param = *new_piter++;
1157      if (!param->name().size() && new_param->name().size())
1158        param->set_name(new_param->name());
1159    }
1160  }
1161  else
1162  {
1163    // Decode the function name
1164    std::string realname;
1165    translate_function_name(encname, realname, returnType);
1166    // Name is same as realname, but with parameters added
1167    std::string name = realname + format_parameters(params);
1168    // Append const after params if this is a const function
1169  
1170    // Figure out postmodifiers
1171    std::vector<std::string> postmod;
1172    if (is_const) 
1173    {
1174      name += "const";
1175      postmod.push_back("const");
1176    }
1177
1178    // Create ASG::Function object
1179    func = my_builder->add_function(my_lineno, name, premod, returnType, postmod, realname, is_template);
1180    func->parameters() = params;
1181  }
1182  add_comments(func, my_declaration);
1183  add_comments(func, dynamic_cast<PTree::Declarator*>(decl));
1184
1185  // if storing links, find name
1186  if (sxr_)
1187  {
1188    // Store for use by TranslateFunctionImplementation
1189    my_function = func;
1190    
1191    // Do decl type first
1192    if (my_store_decl && PTree::second(my_declaration))
1193      sxr_->xref(PTree::second(my_declaration), returnType);
1194
1195    p = decl;
1196    while (p && p->car()->is_atom() && (*p->car() == '*' || *p->car() == '&'))
1197      p = PTree::rest(p);
1198    if (p)
1199      // p should now be at the name
1200      sxr_->xref(p->car(), func);
1201  }
1202  return 0;
1203}
1204
1205PTree::Node*
1206Walker::translate_variable_declarator(PTree::Node *decl, bool is_const)
1207{
1208  STrace trace("translate_variable_declarator");
1209  // Variable declaration. Restart decoding
1210  PTree::Encoding encname = decl->encoded_name();
1211  PTree::Encoding enctype = decl->encoded_type();
1212  my_decoder->init(enctype);
1213  // Get type
1214  Types::Type* type = my_decoder->decodeType();
1215  std::string name;
1216  if (my_decoder->isName(encname))
1217    name = my_decoder->decodeName(encname);
1218  else if (encname.at(0) == 'Q')
1219  {
1220    LOG("Scoped name in variable decl!");
1221    nodeLOG(decl);
1222    return 0;
1223  }
1224  else
1225  {
1226    LOG("Unknown name in variable decl!");
1227    nodeLOG(decl);
1228    return 0;
1229  }
1230  // TODO: implement sizes support
1231  std::vector<size_t> sizes;
1232  std::string var_type = my_builder->scope()->type();
1233  if (var_type == "class" || var_type == "struct" || var_type == "union")
1234    var_type = "data member";
1235  else
1236  {
1237    if (var_type == "function")
1238      var_type = "local";
1239    var_type += is_const ? " constant" : " variable";
1240  }
1241  ASG::Declaration* var;
1242
1243  if (is_const)
1244  {
1245    std::string value;
1246    if (PTree::length(decl) == 3)
1247      value = PTree::reify(PTree::nth(decl, 2));
1248    var = my_builder->add_constant(my_lineno, name, type, var_type, value);
1249  }
1250  else
1251    var = my_builder->add_variable(my_lineno, name, type, false, var_type);
1252  add_comments(var, my_declaration);
1253  add_comments(var, dynamic_cast<PTree::Declarator*>(decl));
1254  // if storing links, find name
1255  if (sxr_)
1256  {
1257    // Do decl type first
1258    if (my_store_decl && PTree::second(my_declaration))
1259      sxr_->xref(PTree::second(my_declaration), type);
1260    
1261    PTree::Node *p = decl;
1262    while (p && p->car()->is_atom() && 
1263           (*p->car() == '*' || *p->car() == '&' || *p->car() == "const"))
1264    {
1265      // Link the const keyword
1266      if (*p->car() == "const")
1267        sxr_->span(p->car(), "keyword");
1268      p = PTree::rest(p);
1269    }
1270    if (p)
1271    {
1272      // p should now be at the name
1273      sxr_->xref(p->car(), var);
1274      
1275      // Next might be '=' then expr
1276      p = PTree::rest(p);
1277      if (p && p->car() && *p->car() == '=')
1278      {
1279        p = PTree::rest(p);
1280        if (p && p->car())
1281          translate(p->car());
1282      }
1283    }
1284  }
1285  return 0;
1286}
1287
1288// Fills the vector of Parameter types by parsing p_params.
1289void
1290Walker::translate_parameters(PTree::Node *p_params, std::vector<ASG::Parameter*>& params)
1291{
1292  STrace trace("Walker::translate_parameters");
1293  if (PTree::length(p_params) == 1 && *p_params->car() == "void") return;
1294  while (p_params)
1295  {
1296    // A parameter has a type, possibly a name and possibly a value
1297    std::string name, value;
1298    ASG::Parameter::Mods premods, postmods;
1299    if (*p_params->car() == ',')
1300      p_params = p_params->cdr();
1301    PTree::Node *param = PTree::first(p_params);
1302    // The type is stored in the encoded type string already
1303    Types::Type* type = my_decoder->decodeType();
1304    if (!type)
1305    {
1306      std::cerr << "Premature end of decoding!" << std::endl;
1307      break; // 0 means end of encoding
1308    }
1309    if (PTree::length(param) == 3)
1310    {
1311      PTree::Declarator *decl = static_cast<PTree::Declarator*>(PTree::nth(param, 2));
1312      name = parse_name(decl->name());
1313      value = parse_name(decl->initializer());
1314      // Link type
1315      if (sxr_ && PTree::nth(param, 1)) sxr_->xref(PTree::nth(param, 1), type);
1316
1317      // Skip keywords (eg: register) which are Leaves
1318      PTree::Node *atom = PTree::nth(param, 0);
1319      if (atom) premods.push_back(parse_name(atom));
1320    }
1321    // Add the ASG.Parameter type to the list
1322    params.push_back(new ASG::Parameter(premods, type, postmods, name, value));
1323    p_params = PTree::rest(p_params);
1324  }
1325}
1326
1327void Walker::translate_function_name(const PTree::Encoding &encname, std::string& realname, Types::Type*& returnType)
1328{
1329  STrace trace("Walker::translate_function_name");
1330  if (my_decoder->isName(encname))
1331  {
1332    if (encname.at(1) == '@')
1333    {
1334      // conversion operator
1335      my_decoder->init(encname);
1336      my_decoder->iter() += 2;
1337      returnType = my_decoder->decodeType();
1338      realname = "("+my_type_formatter->format(returnType)+")";
1339    }
1340    else
1341    {
1342      // simple name
1343      realname = my_decoder->decodeName(encname);
1344      // operator names are missing the 'operator', add it back
1345      char c = realname[0];
1346      if (c == '+' || c == '-' || c == '*' || c == '/' || c == '%'
1347          || c == '^' || c == '&' || c == '!' || c == '=' || c == '<'
1348          || c == '>' || c == ',' || c == '(' || c == '['
1349          || (c == '~' && realname[1] == 0))
1350        realname = "operator"+realname;
1351    }
1352  }
1353  else if (encname.at(0) == 'Q')
1354  {
1355    // If a function declaration has a scoped name, then it is not
1356    // declaring a new function in that scope and can be ignored in
1357    // the context of synopsis.
1358    // TODO: maybe needed for syntax stuff?
1359    return;
1360  }
1361  else if (encname.at(0) == 'T')
1362  {
1363    // Template specialisation.
1364    // blah<int, int> is T4blah2ii ---> realname = foo<int,int>
1365    my_decoder->init(encname);
1366    code_iter& iter = ++my_decoder->iter();
1367    realname = my_decoder->decodeName()+"<";
1368    code_iter tend = iter + (*iter - 0x80u);
1369    iter++; // For some reason, putting this in prev line causes error with 3.2
1370    bool first = true;
1371    // Append type names to realname
1372    while (iter <= tend)
1373    {
1374      /*Types::Type* type = */my_decoder->decodeType();
1375      if (!first) realname+=",";
1376      else first=false;
1377      realname += "type"; //type->ToString();
1378    }
1379    realname += ">";
1380  }
1381  else
1382    std::cerr << "Warning: Unknown function name: " << encname << std::endl;
1383}
1384
1385//. Class or Enum
1386PTree::Node*
1387Walker::translate_type_specifier(PTree::Node *tspec)