Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Parser/C++/syn/swalker.cc
    1| // Synopsis C++ Parser: swalker.cc source file
    2| // Implementation of the common parts of the SWalker class.
    3| // See also swalker-syntax.cc for the more syntax-highlighting oriented member
    4| // functions.
    5| 
    6| // $Id: swalker.cc,v 1.74 2002/12/23 13:47:36 chalky Exp $
    7| //
    8| // This file is a part of Synopsis.
    9| // Copyright (C) 2000-2002 Stephen Davies
   10| // Copyright (C) 2000, 2001 Stefan Seefeld
   11| //
   12| // Synopsis is free software; you can redistribute it and/or modify it
   13| // under the terms of the GNU General Public License as published by
   14| // the Free Software Foundation; either version 2 of the License, or
   15| // (at your option) any later version.
   16| //
   17| // This program is distributed in the hope that it will be useful,
   18| // but WITHOUT ANY WARRANTY; without even the implied warranty of
   19| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   20| // General Public License for more details.
   21| //
   22| // You should have received a copy of the GNU General Public License
   23| // along with this program; if not, write to the Free Software
   24| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   25| // 02111-1307, USA.
   26| //
   27| // $Log: swalker.cc,v $
   28| // Revision 1.74  2002/12/23 13:47:36  chalky
   29| // Reset namespace filenames for each namespace declaration.
   30| //
   31| // Revision 1.73  2002/12/09 08:27:22  chalky
   32| // Ensure tail comments have the right file/line set.
   33| //
   34| // Revision 1.72  2002/12/09 04:01:01  chalky
   35| // Added multiple file support to parsers, changed AST datastructure to handle
   36| // new information, added a demo to demo/C++. AST Declarations now have a
   37| // reference to a SourceFile (which includes a filename) instead of a filename.
   38| //
   39| // Revision 1.71  2002/11/24 01:21:30  chalky
   40| // Added support for declarations in if/switch conditions
   41| //
   42| // Revision 1.70  2002/11/17 12:11:44  chalky
   43| // Reformatted all files with astyle --style=ansi, renamed fakegc.hh
   44| //
   45| // Revision 1.69  2002/11/03 05:22:34  chalky
   46| // Add support for long long literals
   47| //
   48| // Revision 1.68  2002/11/02 06:37:38  chalky
   49| // Allow non-frames output, some refactoring of page layout, new modules.
   50| //
   51| // Revision 1.67  2002/10/29 14:59:27  chalky
   52| // Better support for names of specialized templates with spaces in the
   53| // parameters
   54| //
   55| // Revision 1.66  2002/10/29 02:39:57  chalky
   56| // Changes to compile with g++-3.2
   57| //
   58| // Revision 1.65  2002/10/28 06:14:39  chalky
   59| // Rename class/struct/union variables to "data members"
   60| //
   61| // Revision 1.64  2002/10/27 09:55:15  chalky
   62| // Fix parameter name recognition for function pointer parameters
   63| //
   64| // Revision 1.63  2002/10/27 07:23:30  chalky
   65| // Typeof support. Generate Function when appropriate. Better emulation support.
   66| //
   67| // Revision 1.62  2002/10/25 05:13:57  chalky
   68| // Include the 'operator' in operator names
   69| //
   70| // Revision 1.61  2002/10/25 03:43:37  chalky
   71| // Close templates when there's an exception
   72| //
   73| // Revision 1.60  2002/10/25 02:49:51  chalky
   74| // Support templated forward class declarations
   75| //
   76| // Revision 1.59  2002/10/20 16:49:26  chalky
   77| // Fix bug with methods in templates
   78| //
   79| // Revision 1.58  2002/10/20 15:38:10  chalky
   80| // Much improved template support, including Function Templates.
   81| //
   82| // Revision 1.57  2002/10/11 07:37:29  chalky
   83| // Fixed problem with comments and setting a basename
   84| //
   85| // Revision 1.56  2002/10/11 05:58:21  chalky
   86| // Better memory management. Better comment proximity detection.
   87| //
   88| // Revision 1.55  2002/09/20 09:51:13  chalky
   89| // Don't keep comments originating from different file than declaration
   90| // Work around bug in g++ 3.2 ? (*iter++ thing)
   91| //
   92| // Revision 1.54  2002/08/23 08:30:08  chalky
   93| // Add ability to parse typeid constructs, for boost.
   94| //
   95| // Revision 1.53  2002/04/26 01:21:14  chalky
   96| // Bugs and cleanups
   97| //
   98| // Revision 1.52  2002/03/07 14:12:44  chalky
   99| // Better parsing of complex sources like boost
  100| //
  101| 
  102| #include <iostream>
  103| #include <string>
  104| #include <typeinfo>
  105| #include <sstream>
  106| #include <algorithm>
  107| 
  108| #include <occ/ptree.h>
  109| #include <occ/parse.h>
  110| 
  111| #include "swalker.hh"
  112| #include "strace.hh"
  113| #include "type.hh"
  114| #include "ast.hh"
  115| #include "builder.hh"
  116| #include "decoder.hh"
  117| #include "dumper.hh"
  118| //#include "link_map.hh"
  119| #include "linkstore.hh"
  120| #include "lookup.hh"
  121| #include "filter.hh"
  122| 
  123| using namespace AST;
  124| 
  125| // ------------------------------------------------------------------
  126| //                 -- CLASS STrace --
  127| // ------------------------------------------------------------------
  128| 
  129| #ifdef DO_TRACE
  130| // Class variable definitions
  131| int STrace::slevel = 0, STrace::dlevel = 0;
  132| std::ostringstream* STrace::stream = 0;
  133| STrace::string_list STrace::m_list;
  134| std::ostream& STrace::operator <<(Ptree* p)
  135| {
  136|     std::ostream& out = operator <<("-");
  137|     p->Display2(out);
  138|     return out;
  139| }
  140| #endif
  141| 
  142| // ------------------------------------------------------------------
  143| //                 -- CLASS SWalker --
  144| // ------------------------------------------------------------------
  145| 
  146| SWalker *SWalker::g_swalker = 0;
  147| 
  148| // ------------------------------------
  149| // SWalker Constructor
  150| SWalker::SWalker(FileFilter* filter, Parser* parser, Builder* builder, Program* program)
  151|         : Walker(parser),
  152|         m_parser(parser),
  153|         m_builder(builder),
  154|         m_filter(filter),
  155|         m_program(program),
  156|         m_decoder(new Decoder(m_builder)),
  157|         m_declaration(0),
  158|         m_template(0),
  159|         m_filename_ptr(0),
  160|         m_file(NULL),
  161|         m_lineno(0),
  162|         m_extract_tails(false),
  163|         m_links(0),
  164|         m_store_decl(false),
  165|         m_type_formatter(new TypeFormatter()),
  166|         m_function(0),
  167|         m_type(0),
  168|         m_scope(0),
  169|         m_postfix_flag(Postfix_Var)
  170| {
  171|     g_swalker = this; // FIXME: is this needed?
  172|     m_builder->set_swalker(this);
  173|     m_lookup = m_builder->lookup();
  174| }
  175| 
  176| // Destructor
  177| SWalker::~SWalker()
  178| {
  179|     delete m_decoder;
  180|     delete m_type_formatter;
  181|     if (m_links)
  182|         delete m_links;
  183| }
  184| 
  185| // The name returned is just the node's text if the node is a leaf. Otherwise,
  186| // the ToString method of Ptree is used, which is rather expensive since it
  187| // creates a temporary write buffer and reifies the node tree into it.
  188| std::string
  189| SWalker::parse_name(Ptree *node) const
  190| {
  191|     // STrace trace("SWalker::parse_name");
  192|     if (node && node->IsLeaf())
  193|         return std::string(node->GetPosition(), node->GetLength());
  194|     return node->ToString();
  195| }
  196| void
  197| SWalker::set_store_links(LinkStore* links)
  198| {
  199|     m_links = links;
  200| }
  201| 
  202| int SWalker::line_of_ptree(Ptree* node)
  203| {
  204|     update_line_number(node);
  205|     return m_lineno;
  206| }
  207| 
  208| // Updates the line number stored in this SWalker instance, and the filename
  209| // stored in the Builder instance at m_builder. The filename is only set if
  210| // the actual char* changed (which only happens when the preprocessor places
  211| // another #line directive)
  212| void SWalker::update_line_number(Ptree* ptree)
  213| {
  214|     // Ask the Parser for the linenumber of the ptree. This used to be
  215|     // expensive until I hacked buffer.cc to cache the last line number found.
  216|     // Now it's okay as long as you are looking for lines sequentially.
  217|     charfname;
  218|     int fname_len;
  219|     m_lineno = m_parser->LineNumber(ptree->LeftMost(), fnamefname_len);
  220|     if (fname != m_filename_ptr)
  221|     {
  222|         m_filename_ptr = fname;
  223|         m_file = m_filter->get_sourcefile(fnamefname_len);
  224|         m_builder->set_file(m_file);
  225|     }
  226| }
  227| 
  228| AST::Commentmake_Comment(SourceFile* file, int line, Ptree* first, bool suspect=false)
  229| {
  230|     return new AST::Comment(file, line, first->ToString(), suspect);
  231| }
  232| Leafmake_Leaf(char* pos, int len)
  233| {
  234|     return new Leaf(pos, len);
  235| }
  236| // Adds the given comments to the given declaration. If m_links is set,
  237| // then syntax highlighting information is also stored.
  238| void
  239| SWalker::add_comments(AST::Declaration* decl, Ptree* node)
  240| {
  241|     if (node == NULL)
  242|         return;
  243| 
  244|     AST::Comment::vector comments_to_add;
  245| 
  246|     // First, make sure that node is a list of comments
  247|     if (node->What() == ntDeclaration)
  248|         node = static_cast<PtreeDeclaration*>(node)->GetComments();
  249| 
  250|     // Loop over all comments in the list
  251|     for (Ptreenext = node->Rest(); node && !node->IsLeaf(); next = node->Rest())
  252|     {
  253|         Ptreefirst = node->First();
  254|         if (!first || !first->IsLeaf())
  255|         {
  256|             node = next;
  257|             continue;
  258|         }
  259| 
  260|         update_line_number(node);
  261|         // Make sure comment is in same file!
  262|         if (decl && (m_file != decl->file()))
  263|         {
  264|             node = next;
  265|             // Empty list of comments to add: an #include in the middle is not
  266|             // allowed!
  267|             comments_to_add.clear();
  268|             continue;
  269|         }
  270| 
  271|         // Check if comment is continued, eg: consecutive C++ comments
  272|         while (next && next->First() && next->First()->IsLeaf())
  273|         {
  274|             if (strncmp(next->First()->GetPosition(), "//"2))
  275|                 break;
  276|             charnext_pos = next->First()->GetPosition();
  277|             charstart_pos = node->First()->GetPosition();
  278|             charcurr_pos = start_pos + node->First()->GetLength();
  279|             // Must only be whitespace between current comment and next
  280|             // and only one newline
  281|             int newlines = 0;
  282|             while (curr_pos < next_pos && strchr(" \t\r\n", *curr_pos))
  283|                 if (*curr_pos == '\n' && newlines > 0)
  284|                     break;
  285|                 else if (*curr_pos++ == '\n')
  286|                     ++newlines;
  287|             if (curr_pos < next_pos)
  288|                 break;
  289|             // Current comment stretches to end of next
  290|             int len = int(next_pos - start_pos + next->First()->GetLength());
  291|             //node->SetCar(first = new Leaf(start_pos, len));
  292|             node->SetCar(first = make_Leaf(start_poslen));
  293|             // Skip the combined comment
  294|             next = next->Rest();
  295|         }
  296| 
  297|         // Ensure that there is no more than one newline between the comment and
  298|         // the declaration. We assume that the declaration is the next
  299|         // non-comment thing (which could be a bad assumption..)
  300|         // If extract_tails is set, then comments separated by a space are still
  301|         // included, but are marked as suspect for the Linker to deal with
  302|         bool suspect = false;
  303|         charpos = first->GetPosition() + first->GetLength();
  304|         while (*pos && strchr(" \t\r", *pos))
  305|             ++pos;
  306|         if (*pos == '\n')
  307|         {
  308|             ++pos;
  309|             // Found only allowed \n
  310|             while (*pos && strchr(" \t\r", *pos))
  311|                 ++pos;
  312|             if (*pos == '\n' || !strncmp(pos"/*"2))
  313|             {
  314|                 // 1. More than one newline.. skip entire comment and move onto next.
  315|                 // 2. This comment is followed by a /*, so ignore this one
  316|                 // If extract_tails is set, we keep it anyway but mark as suspect
  317|                 if (!m_extract_tails)
  318|                 {
  319|                     node = next;
  320|                     continue;
  321|                 }
  322|                 else
  323|                     suspect = true;
  324|             }
  325|         }
  326| 
  327|         if (decl)
  328|         {
  329|             //AST::Comment* comment = new AST::Comment("", 0, first->ToString(), suspect);
  330|             AST::Commentcomment = make_Comment(m_file0firstsuspect);
  331|             //decl->comments().push_back(comment);
  332|             comments_to_add.push_back(comment);
  333|         }
  334|         if (m_links)
  335|             m_links->long_span(first"file-comment");
  336|         // Set first to nil so we dont accidentally do them twice (eg:
  337|         // when parsing expressions)
  338|         node->SetCar(nil);
  339|         node = next;
  340|     }
  341| 
  342|     // Now add the comments, if applicable
  343|     if (decl && comments_to_add.size())
  344|     {
  345|         AST::Comment::vector::iterator i_comment = comments_to_add.begin();
  346|         while (i_comment != comments_to_add.end())
  347|             decl->comments().push_back(*i_comment++);
  348|     }
  349| }
  350| 
  351| // -- These methods implement add_comments for various node types that store
  352| // comment pointers
  353| void SWalker::add_comments(AST::Declaration* decl, CommentedLeaf* node)
  354| {
  355|     if (node)
  356|         add_comments(declnode->GetComments());
  357| }
  358| void SWalker::add_comments(AST::Declaration* decl, PtreeDeclaration* node)
  359| {
  360|     if (node)
  361|         add_comments(declnode->GetComments());
  362| }
  363| void SWalker::add_comments(AST::Declaration* decl, PtreeDeclarator* node)
  364| {
  365|     if (node)
  366|         add_comments(declnode->GetComments());
  367| }
  368| void SWalker::add_comments(AST::Declaration* decl, PtreeNamespaceSpec* node)
  369| {
  370|     if (node)
  371|         add_comments(declnode->GetComments());
  372| }
  373| void SWalker::find_comments(Ptree* node)
  374| {
  375|     Ptreeleaf, *parent;
  376|     leaf = FindLeftLeaf(nodeparent);
  377|     if (leaf)
  378|         add_comments(NULL, dynamic_cast<CommentedLeaf*>(leaf));
  379| }
  380| 
  381| PtreeSWalker::TranslateArgDeclList(boolPtree*, Ptree*)
  382| {
  383|     STrace trace("SWalker::TranslateArgDeclList NYI");
  384|     return 0;
  385| }
  386| PtreeSWalker::TranslateInitializeArgs(PtreeDeclarator*, Ptree*)
  387| {
  388|     STrace trace("SWalker::TranslateInitializeArgs NYI");
  389|     return 0;
  390| }
  391| PtreeSWalker::TranslateAssignInitializer(PtreeDeclarator*, Ptree*)
  392| {
  393|     STrace trace("SWalker::TranslateAssignInitializer NYI");
  394|     return 0;
  395| }
  396| //Class* SWalker::MakeClassMetaobject(Ptree*, Ptree*, Ptree*) { STrace trace("SWalker::MakeClassMetaobject NYI"); return 0; }
  397| //Ptree* SWalker::TranslateClassSpec(Ptree*, Ptree*, Ptree*, Class*) { STrace trace("SWalker::TranslateClassSpec NYI"); return 0; }
  398| //Ptree* SWalker::TranslateClassBody(Ptree*, Ptree*, Class*) { STrace trace("SWalker::TranslateClassBody NYI"); return 0; }
  399| //Ptree* SWalker::TranslateTemplateInstantiation(Ptree*, Ptree*, Ptree*, Class*) { STrace trace("SWalker::TranslateTemplateInstantiation NYI"); return 0; }
  400| 
  401| // Format the given parameters. m_type_formatter is used to format the given
  402| // list of parameters into a string, suitable for use as the name of a
  403| // Function object.
  404| std::string SWalker::format_parameters(AST::Parameter::vector& params)
  405| {
  406|     // TODO: Tell formatter to expand typedefs! Eg: this function uses a typedef
  407|     // in implementation, but not for declaration in the class!!!!!!
  408|     AST::Parameter::vector::iterator iter = params.begin(), end = params.end();
  409|     if (iter == end)
  410|         return "()";
  411|     // Set scope for formatter
  412|     AST::Scope* scope = m_builder->scope();
  413|     if (scope)
  414|         m_type_formatter->push_scope(scope->name());
  415|     else
  416|     {
  417|         ScopedName empty;
  418|         m_type_formatter->push_scope(empty);
  419|     }
  420|     // Format the parameters one at a time
  421|     std::ostringstream buf;
  422|     buf << "(" << m_type_formatter->format((*iter++)->type());
  423|     while (iter != end)
  424|         buf << "," << m_type_formatter->format((*iter++)->type());
  425|     buf << ")";
  426|     m_type_formatter->pop_scope();
  427|     return buf.str();
  428| }
  429| 
  430| 
  431| 
  432| 
  433| //
  434| // Translate Methods
  435| //
  436| 
  437| // Overrides Walker::Translate to catch any exceptions
  438| void
  439| SWalker::Translate(Ptree* node)
  440| {
  441|     STrace trace("SWalker::Translate");
  442|     try
  443|     {
  444|         Walker::Translate(node);
  445|     }
  446|     // Debug and non-debug modes handle these very differently
  447| #ifdef DEBUG
  448|     catch (const TranslateError& e)
  449|     {
  450|         if (e.node)
  451|             node = e.node;
  452|         char* fname;
  453|         int fname_len;
  454|         int lineno = m_parser->LineNumber(node->LeftMost(), fname, fname_len);
  455|         std::ostringstream buf;
  456|         buf << " (" << std::string(fname, fname_len) << ":" << lineno << ")";
  457|         LOG("Warning: An exception occurred:" << buf.str());
  458|         LOG("- " << e.str());
  459|     }
  460|     catch (const std::exception& e)
  461|     {
  462|         LOG("Warning: An exception occurred: " << e.what());
  463|         nodeLOG(node);
  464|     }
  465|     catch (...)
  466|     {
  467|         LOG("Warning: An exception occurred (unknown) at:");
  468|         nodeLOG(node);
  469|     }
  470| #else
  471|     catch (const TranslateError& e)
  472|     {
  473|         // This error usually means that the syntax highlighting failed, and
  474|         // can be safely ignored
  475|     }
  476|     catch (const std::exception& e)
  477|     {
  478|         std::cout << "Warning: An exception occurred: " << e.what() << std::endl;
  479|         std::cout << "At: ";
  480|         charfname;
  481|         int fname_len;
  482|         int lineno = m_parser->LineNumber(node->LeftMost(), fnamefname_len);
  483|         std::cout << " (" << std::string(fnamefname_len) << ":" << lineno << ")" << std::endl;
  484|     }
  485|     catch (...)
  486|     {
  487|         std::cout << "Warning: An unknown exception occurred: " << std::endl;
  488|         std::cout << "At: ";
  489|         charfname;
  490|         int fname_len;
  491|         int lineno = m_parser->LineNumber(node->LeftMost(), fnamefname_len);
  492|         std::cout << " (" << std::string(fnamefname_len) << ":" << lineno << ")" << std::endl;
  493|     }
  494| #endif
  495| }
  496| 
  497| // Default translate, usually means a literal
  498| PtreeSWalker::TranslatePtree(Ptree* node)
  499| {
  500|     // Determine type of node
  501|     charstr = node->ToString();
  502|     if (*str >= '0' && *str <= '9' || *str == '.')
  503|     {
  504|         // Assume whole node is a number
  505|         if (m_links)
  506|             m_links->span(node"file-number");
  507|         // TODO: decide if Long, Float, Double, etc
  508|         const charnum_type = (*str == '.' ? "double" : "int");
  509|         while (*++str)
  510|         {
  511|             if (*str >= '0' && *str <= '9')
  512|                 ;
  513|             else if (*str == 'e' || *str == 'E')
  514|             {
  515|                 // Might be followed by + or -
  516|                 ++str;
  517|                 if (*str == '+' || *str == '-')
  518|                     ++str;
  519|             }
  520|             else if (*str == '.')
  521|                 num_type = "double";
  522|             else if (*str == 'f' || *str == 'F')
  523|             {
  524|                 num_type = "float";
  525|                 break;
  526|             }
  527|             else if (*str == 'l' || *str == 'L')
  528|             {
  529|                 if (num_type == "int")
  530|                     num_type = "long";
  531|                 else if (num_type == "long")
  532|                     num_type = "long long";
  533|                 else if (num_type == "unsigned")
  534|                     num_type = "unsigned long";
  535|                 else if (num_type == "float")
  536|                     num_type = "long double";
  537|                 else
  538|                     std::cout << "Unknown num type: " << num_type << std::endl;
  539|             }
  540|             else if (*str == 'u' || *str == 'U')
  541|             {
  542|                 if (num_type == "int")
  543|                     num_type = "unsigned";
  544|                 else if (num_type == "long")
  545|                     num_type = "unsigned long";
  546|                 else
  547|                     std::cout << "Unknown num type: " << num_type << std::endl;
  548|             }
  549|             else
  550|                 // End of numeric constant
  551|                 break;
  552|         }
  553|         m_type = m_lookup->lookupType(num_type);
  554|     }
  555|     else if (*str == '\'')
  556|     {
  557|         // Whole node is a char literal
  558|         if (m_links)
  559|             m_links->span(node"file-string");
  560|         m_type = m_lookup->lookupType("char");
  561|     }
  562|     else if (*str == '"')
  563|     {
  564|         // Assume whole node is a string
  565|         if (m_links)
  566|             m_links->span(node"file-string");
  567|         m_type = m_lookup->lookupType("char");
  568|         Types::Type::Mods prepost;
  569|         pre.push_back("const");
  570|         post.push_back("*");
  571|         m_type = new Types::Modifier(m_type, pre, post);
  572|     }
  573|     else if (*str == '/' && !node->IsLeaf())
  574|     {
  575|         // Assume comment. Must be a list of comments!
  576|         AST::Declarationdecl;
  577|         update_line_number(node);
  578|         decl = m_builder->add_tail_comment(m_lineno);
  579|         add_comments(declnode);
  580| 
  581|     }
  582|     else
  583|     {
  584| #ifdef DEBUG
  585|         STrace trace("SWalker::TranslatePtree");
  586|         LOG("Warning: Unknown Ptree "<<node->What());
  587|         nodeLOG(node);
  588|         //*((char*)0) = 1; // force breakpoint, or core dump :)
  589| #endif
  590| 
  591|     }
  592|     return 0;
  593| }
  594| 
  595| //. NamespaceSpec
  596| //. [ namespace <identifier> [{ body }] ]
  597| Ptree*
  598| SWalker::TranslateNamespaceSpec(Ptree* def)
  599| {
  600|     STrace trace("SWalker::TranslateNamespaceSpec");
  601| 
  602|     PtreepNamespace = def->First();
  603|     PtreepIdentifier = def->Second();
  604|     PtreepBody = def->Third();
  605| 
  606|     if (m_links)
  607|         m_links->span(pNamespace"file-keyword");
  608|     else
  609|         update_line_number(def);
  610| 
  611|     // Start the namespace
  612|     AST::Namespacens;
  613|     if (pIdentifier)
  614|     {
  615|         ns = m_builder->start_namespace(parse_name(pIdentifier), NamespaceNamed);
  616|         ns->set_file(m_file);
  617|     }
  618|     else
  619|         ns = m_builder->start_namespace(m_file->filename(), NamespaceAnon);
  620| 
  621|     // Add comments
  622|     add_comments(ns, dynamic_cast<PtreeNamespaceSpec*>(def));
  623|     if (m_links && Ptree::First(pIdentifier))
  624|         m_links->link(pIdentifierns);
  625| 
  626|     // Translate the body
  627|     Translate(pBody);
  628| 
  629|     // End the namespace
  630|     m_builder->end_namespace();
  631|     return 0;
  632| }
  633| 
  634| //. [ : (public|private|protected|nil) <name> {, ...} ]
  635| std::vector<Inheritance*> SWalker::TranslateInheritanceSpec(Ptree *node)
  636| {
  637|     STrace trace("PyWalker::TranslateInheritanceSpec");
  638|     std::vector<Inheritance*> ispec;
  639|     Types::Type *type;
  640|     while (node)
  641|     {
  642|         node = node->Cdr(); // skip : or ,
  643|         // the attributes
  644|         std::vector<std::stringattributes(node->Car()->Length() - 1);
  645|         for (int i = 0i != node->Car()->Length() - 1; ++i)
  646|         {
  647|             attributes[i] = parse_name(node->Car()->Nth(i));
  648|             if (m_links)
  649|                 m_links->span(node->Car()->Nth(i), "file-keyword");
  650|         }
  651|         // look up the parent type
  652|         Ptreename = node->Car()->Last()->Car();
  653|         if (name->IsLeaf())
  654|         {
  655|             try
  656|             {
  657|                 type = m_lookup->lookupType(parse_name(name));
  658|             }
  659|             catch (const TranslateError)
  660|             {
  661|                 // Ignore error, and put an Unknown in, instead
  662|                 ScopedName uname;
  663|                 uname.push_back(parse_name(name));
  664|                 type = new Types::Unknown(uname);
  665|             }
  666|         }
  667|         else
  668|         {
  669|             charencname = name->GetEncodedName();
  670|             m_decoder->init(encname);
  671|             type = m_decoder->decodeType();
  672|         }
  673|         if (m_links)
  674|             m_links->link(nametype);
  675| 
  676|         node = node->Cdr();
  677|         // add it to the list
  678|         ispec.push_back(new AST::Inheritance(type, attributes));
  679|     }
  680|     return ispec;
  681| }
  682| 
  683| 
  684| Ptree*
  685| SWalker::TranslateClassSpec(Ptree* node)
  686| {
  687|     // REVISIT: figure out why this method is so long
  688|     STrace trace("SWalker::TranslateClassSpec");
  689|     enum { SizeForwardDecl = 2, SizeAnonClass = 3, SizeClass = 4 };
  690| 
  691|     AST::Parameter::vectoris_template = m_template;
  692|     m_template = NULL;
  693| 
  694|     int size = Ptree::Length(node);
  695| 
  696|     if (size == SizeForwardDecl)
  697|     {
  698|         // Forward declaration
  699|         // [ class|struct <name> ]
  700|         std::string name = parse_name(node->Second());
  701|         if (is_template)
  702|             LOG("Templated class forward declaration " << name);
  703|         m_builder->add_forward(m_linenonameis_template);
  704|         if (m_links)
  705|         // highlight the comments, at least
  706|             PtreeClassSpeccspec = static_cast<PtreeClassSpec*>(node);
  707|             add_comments(NULL, cspec->GetComments());
  708|         }
  709|         return 0;
  710|     }
  711|     PtreepClass = node->First();
  712|     PtreepName = NULL, *pInheritance = NULL;
  713|     PtreepBody = NULL;
  714|     if (size == SizeClass)
  715|     {
  716|         // [ class|struct <name> <inheritance> [{ body }] ]
  717|         pName = node->Nth(1);
  718|         pInheritance = node->Nth(2);
  719|         pBody = node->Nth(3);
  720|     }
  721|     else if (size == SizeAnonClass)
  722|         // An anonymous struct. OpenC++ encodes us a unique
  723|         // (may be qualified if nested) name
  724|         // [ struct [nil nil] [{ ... }] ]
  725|         pBody = node->Nth(2);
  726|     else
  727|         throw nodeERROR(node, "Class node has bad length: " << size);
  728| 
  729|     if (m_links)
  730|         m_links->span(pClass"file-keyword");
  731|     else
  732|         update_line_number(node);
  733| 
  734|     // Create AST.Class object
  735|     AST::Class *clas;
  736|     std::string type = parse_name(pClass);
  737|     charencname = node->GetEncodedName();
  738|     m_decoder->init(encname);
  739|     if (encname[0] == 'T')
  740|     {
  741|         // Specialization
  742|         // TODO: deal with this.
  743|         // Eg: /usr/include/g++-3/std/straits.h
  744|         // search: /^struct string_char_traits <char> {/
  745|         // encname: "T\222string_char_traits\201c"
  746|         LOG("Specialization?");
  747|         nodeLOG(node);
  748|         LOG("encname:"<<make_code(encname));
  749|         Types::Parameterizedparam = dynamic_cast<Types::Parameterized*>(m_decoder->decodeTemplate());
  750|         // If a non-type param was found, it's name will be '*'
  751|         for (size_t i = 0i < param->parameters().size(); i++)
  752|             if (Types::Dependentdep = dynamic_cast<Types::Dependent*>(param->parameters()[i])
  753|                )
  754|             {
  755|                 if (dep->name().size() == 1 && dep->name()[0] == "*")
  756|                 {
  757|                     // Find the value of this parameter
  758|                     std::string name = parse_name(pName->Second()->Second()->Nth(i*2));
  759|                     dep->name()[0] = name;
  760|                 }
  761|             }
  762| 
  763|         m_type_formatter->push_scope(m_builder->scope()->name());
  764|         std::string name = m_type_formatter->format(param);
  765|         m_type_formatter->pop_scope();
  766|         clas = m_builder->start_class(m_linenotypenameis_template);
  767|         // TODO: figure out spec stuff, like what to do with vars, link to
  768|         // original template, etc.
  769|     }
  770|     else if (encname[0] == 'Q')
  771|     {
  772|         ScopedName names;
  773|         m_decoder->decodeQualName(names);
  774|         clas = m_builder->start_class(m_linenotypenames);
  775|     }
  776|     else
  777|     {
  778|         std::string name = m_decoder->decodeName();
  779|         clas = m_builder->start_class(m_linenotypenameis_template);
  780|     }
  781|     if (m_links && pName)
  782|         m_links->link(pNameclas);
  783|     LOG("Translating class '" << clas->name() << "'");
  784| 
  785|     // Translate the inheritance spec, if present
  786|     if (pInheritance)
  787|     {
  788|         clas->parents() = TranslateInheritanceSpec(pInheritance);
  789|         m_builder->update_class_base_search();
  790|     }
  791| 
  792|     // Add comments
  793|     PtreeClassSpeccspec = static_cast<PtreeClassSpec*>(node);
  794|     add_comments(clascspec->GetComments());
  795| 
  796|     // Push the impl stack for a cache of func impls
  797|     m_func_impl_stack.push_back(FuncImplVec());
  798| 
  799|     // Translate the body of the class
  800|     TranslateBlock(pBody);
  801| 
  802|     // Translate any func impls inlined in the class
  803|     FuncImplVecvec = m_func_impl_stack.back();
  804|     FuncImplVec::iterator iter = vec.begin();
  805|     while (iter != vec.end())
  806|         TranslateFuncImplCache(*iter++);
  807|     m_func_impl_stack.pop_back();
  808| 
  809|     m_builder->end_class();
  810|     return 0;
  811| }
  812| 
  813| Ptree*
  814| SWalker::TranslateTemplateClass(Ptree* def, Ptree* node)
  815| {
  816|     STrace trace("SWalker::TranslateTemplateClass");
  817|     AST::Parameter::vectorold_params = m_template;
  818|     update_line_number(def);
  819|     m_builder->start_template();
  820|     try
  821|     {
  822|         TranslateTemplateParams(def->Third());
  823|         TranslateClassSpec(node);
  824|     }
  825|     catch (...)
  826|     {
  827|         m_builder->end_template();
  828|         m_template = old_params;
  829|         throw;
  830|     }
  831|     m_builder->end_template();
  832|     m_template = old_params;
  833|     return 0;
  834| }
  835| 
  836| void SWalker::TranslateTemplateParams(Ptree* params)
  837| {
  838|     STrace trace("SWalker::TranslateTemplateParams");
  839|     m_template = new AST::Parameter::vector;
  840|     AST::Parameter::vector& templ_params = *m_template;
  841|     // Declare some default parameter values - these should not be modified!
  842|     std::string name, value;
  843|     AST::Parameter::Mods pre_mods, post_mods;
  844|     while (params)
  845|     {
  846|         Ptree* param = params->First();
  847|         nodeLOG(param);
  848|         if (param->First()->Eq("class") || param->First()->Eq("typename"))
  849|         {
  850|             // Ensure that there is an identifier (it is optional!)
  851|             if (param->Cdr() && param->Second())
  852|             {
  853|                 // This parameter specifies a type, add as dependent
  854|                 Types::Dependent* dep = m_builder->create_dependent(parse_name(param->Second()));
  855|                 m_builder->add
  856|                 (dep);
  857|                 AST::Parameter::Mods paramtype;
  858|                 paramtype.push_back(parse_name(param->First()));
  859|                 templ_params.push_back(new AST::Parameter(paramtype, dep, post_mods, name, value));
  860|             }
  861|             else
  862|             {
  863|                 // Add a parameter, but with no name
  864|                 AST::Parameter::Mods paramtype;
  865|                 paramtype.push_back(parse_name(param->First()));
  866|                 templ_params.push_back(new AST::Parameter(paramtype, NULL, post_mods, name, value));
  867|             }
  868|         }
  869|         else if (param->First()->Eq("template"))
  870|         {
  871|             // A non-type parameter that is templatized
  872|             // eg: template< class A, template<class T> class B = foo > C;
  873|             // FIXME.
  874|             LOG("templated non-type template parameter!");
  875|             nodeLOG(param);
  876|         }
  877|         else
  878|         {
  879|             // This parameter specifies a value or something
  880|             // FIXME can do a lot more here..
  881|             LOG("non-type template parameter! approximating..");
  882|             nodeLOG(param);
  883|             Ptree* p = param->Second();
  884|             while (p && p->Car() && p->Car()->IsLeaf() && (p->Car()->Eq('*') || p->Car()->Eq('&')))
  885|                 p = Ptree::Rest(p);
  886|             std::string name = parse_name(p);
  887|             Types::Dependent* dep = m_builder->create_dependent(name);
  888|             m_builder->add
  889|             (dep);
  890|             // Figure out the type of the param
  891|             m_decoder->init(param->Second()->GetEncodedType());
  892|             Types::Type* param_type = m_decoder->decodeType();
  893|             templ_params.push_back(new AST::Parameter(pre_mods, param_type, post_mods, name, value));
  894|         }
  895|         // Skip comma
  896|         params = Ptree::Rest(params->Rest());
  897|     }
  898|     /*
  899|     Types::Template* templ = new Types::Template(decl->name(), decl, templ_params);
  900|     if (AST::Class* clas = dynamic_cast<AST::Class*>(decl))
  901|       clas->set_template_type(templ);
  902|     else if (AST::Function* func = dynamic_cast<AST::Function*>(decl))
  903|       func->set_template_type(templ);
  904|     std::ostrstream buf;
  905|     buf << "template " << decl->type() << std::ends;
  906|     decl->set_type(buf.str());
  907|     */
  908| }
  909| 
  910| Ptree*
  911| SWalker::TranslateTemplateFunction(Ptree* def, Ptree* node)
  912| {
  913|     STrace trace("SWalker::TranslateTemplateFunction");
  914|     nodeLOG(def);
  915|     nodeLOG(node);
  916|     if (node->What() != ntDeclaration)
  917|     {
  918|         LOG("Warning: Unknown node type in template");
  919|         nodeLOG(def);
  920|         return 0;
  921|     }
  922| 
  923|     LOG("What is: " << node->What());
  924|     LOG("Encoded name is: " << make_code(node->GetEncodedName()));
  925| 
  926|     AST::Parameter::vectorold_params = m_template;
  927|     update_line_number(def);
  928|     m_builder->start_template();
  929|     try
  930|     {
  931|         TranslateTemplateParams(def->Third());
  932|         TranslateDeclaration(node);
  933|     }
  934|     catch (...)
  935|     {
  936|         m_builder->end_template();
  937|         m_template = old_params;
  938|         throw;
  939|     }
  940|     m_builder->end_template();
  941|     m_template = old_params;
  942|     return 0;
  943| }
  944| 
  945| //. Linkage Spec
  946| //. [ extern ["C++"] [{ body }] ]
  947| Ptree*
  948| SWalker::TranslateLinkageSpec(Ptree* node)
  949| {
  950|     STrace trace("SWalker::TranslateLinkageSpec");
  951|     Translate(node->Third());
  952|     return 0;
  953| }
  954| 
  955| //. Block
  956| //. [ { [ <statement>* ] } ]
  957| Ptree*
  958| SWalker::TranslateBlock(Ptree* block)
  959| {
  960|     STrace trace("SWalker::TranslateBlock");
  961|     Ptreerest = Ptree::Second(block);
  962|     while (rest != nil)
  963|     {
  964|         Translate(rest->Car());
  965|         rest = rest->Cdr();
  966|     }
  967|     if (m_extract_tails)
  968|     {
  969|         Ptreeclose = Ptree::Third(block);
  970|         AST::Declarationdecl;
  971|         decl = m_builder->add_tail_comment(m_lineno);
  972|         add_comments(decl, dynamic_cast<CommentedLeaf*>(close));
  973|     }
  974| 
  975|     return 0;
  976| }
  977| 
  978| //. Brace
  979| //. [ { [ <statement>* ] } ]
  980| Ptree*
  981| SWalker::TranslateBrace(Ptree* brace)
  982| {
  983|     STrace trace("SWalker::TranslateBrace");
  984|     Ptreerest = Ptree::Second(brace);
  985|     while (rest != nil)
  986|     {
  987|         Translate(rest->Car());
  988|         rest = rest->Cdr();
  989|     }
  990|     if (m_extract_tails)
  991|     {
  992|         Ptreeclose = Ptree::Third(brace);
  993|         AST::Declarationdecl;
  994|         decl = m_builder->add_tail_comment(m_lineno);
  995|         add_comments(decl, dynamic_cast<CommentedLeaf*>(close));
  996|     }
  997| 
  998|     return 0;
  999| }
 1000| 
 1001| //. TemplateDecl
 1002| //. [ template < [types] > [decl] ]
 1003| Ptree*
 1004| SWalker::TranslateTemplateDecl(Ptree* def)
 1005| {
 1006|     STrace trace("SWalker::TranslateTemplateDecl");
 1007|     Ptreebody = Ptree::Nth(def4);
 1008|     Ptreeclass_spec = GetClassTemplateSpec(body);
 1009|     if(class_spec->IsA(ntClassSpec))
 1010|         TranslateTemplateClass(defclass_spec);
 1011|     else
 1012|         TranslateTemplateFunction(defbody);
 1013|     return 0;
 1014| }
 1015| 
 1016| //. A typeof(expr) expression evaluates to the type of 'expr'. This is a GNU
 1017| //. GCC extension!
 1018| //. Since the OCC parser can't resolve the type properly, we try to do it here
 1019| //. and modify the type of the declarations to set it
 1020| PtreeSWalker::TranslateTypeof(Ptree* spec, Ptree* declarations)
 1021| {
 1022|     STrace trace("SWalker::TranslateTypeof");
 1023|     nodeLOG(spec);
 1024|     charencname = spec->Third()->GetEncodedName();
 1025|     LOG("The name is: " << make_code(encname));
 1026|     LOG("The type is: " << make_code(spec->Third()->GetEncodedType()));
 1027|     // Find the type referred to by the expression
 1028|     if (!m_decoder->isName(encname))
 1029|     {
 1030|         LOG("typeof is not a simple name: ");
 1031|         nodeLOG(spec);
 1032|         return 0;
 1033|     }
 1034|     std::string name = m_decoder->decodeName(encname);
 1035|     LOG("name is " << name);
 1036|     Types::Typetype = m_lookup->lookupType(nametrue);
 1037|     // Find the declaration it refers to
 1038|     Types::Declareddeclared = dynamic_cast<Types::Declared*>(type);
 1039|     if (!declared)
 1040|         return 0;
 1041|     LOG("Looked up " << declared->name());
 1042|     AST::Declarationdecl = declared->declaration();
 1043|     if (!decl)
 1044|         return 0;
 1045|     LOG("Declaration is " << decl->name());
 1046|     // TODO: make this a visitor and support different things
 1047|     if (/*AST::Function* func =*/ dynamic_cast<AST::Function*>(decl))
 1048|     {
 1049|         LOG("decl is a function.");
 1050|         while (declarations)
 1051|         {
 1052|             Ptreedeclarator = declarations->First();
 1053|             declarations = declarations->Rest();
 1054| 
 1055|             if (declarator->What() == ntDeclarator)
 1056|                 ((PtreeDeclarator*)declarator)->SetEncodedType("PFv_v");
 1057|             else
 1058|                 LOG("declarator is " << declarator->What());
 1059|         }
 1060|     }
 1061|     else
 1062|     {
 1063|         LOG("unknown decl type");
 1064|     }
 1065|     nodeLOG(declarations);
 1066|     return 0;
 1067| }
 1068| 
 1069| //. Translates a declaration, either variable, typedef or function
 1070| //. Variables:
 1071| //.  [ [modifiers] name [declarators] ; ]
 1072| //. Function prototype:
 1073| //.  [ [modifiers] name [declarators] ; ]
 1074| //. Function impl:
 1075| //.  [ [modifiers] name declarator [ { ... } ] ]
 1076| //. Typedef:
 1077| //.  ?
 1078| //. Class definition:
 1079| //.  [ [modifiers] [class foo ...] [declarators]? ; ]
 1080| PtreeSWalker::TranslateDeclaration(Ptree* def)
 1081| {
 1082|     STrace trace("SWalker::TranslateDeclaration");
 1083|     // Link any comments added because we are inside a function body
 1084|     if (m_links)
 1085|         find_comments(def);
 1086| 
 1087|     update_line_number(def);
 1088| 
 1089|     m_declaration = def;
 1090|     m_store_decl = true;
 1091|     Ptreedecls = Ptree::Third(def);
 1092| 
 1093|     // Typespecifier may be a class {} etc.
 1094|     TranslateTypespecifier(Ptree::Second(def));
 1095|     // Or it might be a typeof()
 1096|     if (Ptree::Second(def) && Ptree::Second(def)->What() == ntTypeofExpr)
 1097|         TranslateTypeof(Ptree::Second(def), decls);
 1098| 
 1099|     if (decls->IsA(ntDeclarator))
 1100|     {
 1101|         // A single declarator is probably a function impl, but could also be
 1102|         // the declarator in an if or switch condition
 1103|         if (const charencoded_type = decls->GetEncodedType())
 1104|         {
 1105|             // A function may be const, skip the C
 1106|             while (*encoded_type == 'C')
 1107|                 encoded_type++;
 1108|             if (*encoded_type != 'F')
 1109|             {
 1110|                 // Not a function
 1111|                 TranslateDeclarator(decls);
 1112|                 m_declaration = NULL;
 1113|                 return 0;
 1114|             }
 1115|         }
 1116|         TranslateFunctionImplementation(def);
 1117|     }
 1118|     else
 1119|         // if it is a function prototype or a variable declaration.
 1120|         if (!decls->IsLeaf())        // if it is not ";"
 1121|             TranslateDeclarators(decls);
 1122|     m_declaration = NULL;
 1123|     return 0;
 1124| }
 1125| 
 1126| //. [ [ declarator { = <expr> } ] , ... ]
 1127| Ptree*
 1128| SWalker::TranslateDeclarators(Ptree* decls)
 1129| {
 1130|     STrace trace("SWalker::TranslateDeclarators");
 1131|     Ptreerest = decls, *p;
 1132|     while (rest != nil)
 1133|     {
 1134|         p = rest->Car();
 1135|         if (p->IsA(ntDeclarator))
 1136|         {
 1137|             TranslateDeclarator(p);
 1138|             m_store_decl = false;
 1139|         } // if. There is no else..?
 1140|         rest = rest->Cdr();
 1141|         // Skip comma
 1142|         if (rest != nil)
 1143|             rest = rest->Cdr();
 1144|     }
 1145|     return 0;
 1146| }
 1147| 
 1148| //. TranslateDeclarator
 1149| //. Function proto:
 1150| //.   [ { * | & }* name ( [params] ) ]
 1151| //. param:
 1152| //.   [ [types] { [ { * | & }* name ] { = value } } ]
 1153| Ptree*
 1154| SWalker::TranslateDeclarator(Ptree* decl)
 1155| {
 1156|     // REVISIT: Figure out why this method is so HUGE!
 1157|     STrace trace("SWalker::TranslateDeclarator");
 1158|     // Insert code from occ.cc here
 1159|     charencname = decl->GetEncodedName();
 1160|     charenctype = decl->GetEncodedType();
 1161|     if (!encname || !enctype)
 1162|     {
 1163|         std::cout << "encname or enctype null!" << std::endl;
 1164|         return 0;
 1165|     }
 1166| 
 1167|     try
 1168|     {
 1169|         // Decide if this is a function or variable
 1170|         m_decoder->init(enctype);
 1171|         code_iteriter = m_decoder->iter();
 1172|         bool is_const = false;
 1173|         while (*iter == 'C')
 1174|         {
 1175|             ++iter;
 1176|             is_const = true;
 1177|         }
 1178|         if (*iter == 'F')
 1179|             return TranslateFunctionDeclarator(declis_const);
 1180|         else
 1181|             return TranslateVariableDeclarator(declis_const);
 1182|     }
 1183|     catch (const TranslateError& e)
 1184|     {
 1185|         e.set_node(decl);
 1186|         throw;
 1187|     }
 1188|     return 0;
 1189| }
 1190| 
 1191| 
 1192| Ptree*
 1193| SWalker::TranslateFunctionDeclarator(Ptree* decl, bool is_const)
 1194| {
 1195|     STrace trace("SWalker::TranslateFunctionDeclarator");
 1196|     AST::Parameter::vectoris_template = m_template;
 1197|     m_template = NULL;
 1198| 
 1199|     code_iteriter = m_decoder->iter();
 1200|     charencname = decl->GetEncodedName();
 1201| 
 1202|     // This is a function. Skip the 'F'
 1203|     ++iter;
 1204| 
 1205|     // Create parameter objects
 1206|     Ptree *p_params = decl->Rest();
 1207|     while (p_params && !p_params->Car()->Eq('('))
 1208|         p_params = Ptree::Rest(p_params);
 1209|     if (!p_params)
 1210|     {
 1211|         std::cout << "Warning: error finding params!" << std::endl;
 1212|         return 0;
 1213|     }
 1214|     std::vector<AST::Parameter*> params;
 1215|     TranslateParameters(p_params->Second(), params);
 1216|     m_param_cache = params;
 1217| 
 1218|     // Figure out the return type:
 1219|     while (*iter++ != '_')
 1220|         // in case of decoding error this is needed
 1221|     Types::TypereturnType = m_decoder->decodeType();
 1222| 
 1223|     // Figure out premodifiers
 1224|     std::vector<std::stringpremod;
 1225|     Ptreep = Ptree::First(m_declaration);
 1226|     while (p)
 1227|     {
 1228|         premod.push_back(p->ToString());
 1229|         p = Ptree::Rest(p);
 1230|     }
 1231| 
 1232|     AST::Functionfunc = 0;
 1233|     // Find name:
 1234|     if (encname[0] == 'Q')
 1235|     {
 1236|         // The name is qualified, which introduces a bit of difficulty
 1237|         std::vector<std::stringnames;
 1238|         m_decoder->init(encname);
 1239|         m_decoder->decodeQualName(names);
 1240|         names.back() += format_parameters(params);
 1241|         // A qual name must already be declared, so find it:
 1242|         try
 1243|         {
 1244|             Types::Namednamed_type = m_lookup->lookupType(namestrue);
 1245|             func = Types::declared_cast<AST::Function>(named_type);
 1246|         }
 1247|         catch (const Types::wrong_type_cast &)
 1248|         {
 1249|             throw ERROR("Qualified function name wasn't a function:" << names);
 1250|         }
 1251|         // expand param info, since we now have names for them
 1252|         std::vector<AST::Parameter*>::iterator piter = func->parameters().begin();
 1253|         std::vector<AST::Parameter*>::iterator pend = func->parameters().end();
 1254|         std::vector<AST::Parameter*>::iterator new_piter = params.begin();
 1255|         while (piter != pend)
 1256|         {
 1257|             AST::Parameterparam = *piter++, *new_param = *new_piter++;
 1258|             if (!param->name().size() && new_param->name().size())
 1259|                 param->set_name(new_param->name());
 1260|         }
 1261|     }
 1262|     else
 1263|     {
 1264|         // Decode the function name
 1265|         std::string realname;
 1266|         TranslateFunctionName(encnamerealnamereturnType);
 1267|         // Name is same as realname, but with parameters added
 1268|         std::string name = realname + format_parameters(params);
 1269|         // Append const after params if this is a const function
 1270|         if (is_const)
 1271|             name += "const";
 1272|         // Create AST::Function object
 1273|         func = m_builder->add_function(m_linenonamepremodreturnTyperealnameis_template);
 1274|         func->parameters() = params;
 1275|     }
 1276|     add_comments(funcm_declaration);
 1277|     add_comments(func, dynamic_cast<PtreeDeclarator*>(decl));
 1278| 
 1279|     // if storing links, find name
 1280|     if (m_links)
 1281|     {
 1282|         // Store for use by TranslateFunctionImplementation
 1283|         m_function = func;
 1284| 
 1285|         // Do decl type first
 1286|         if (m_store_decl && m_declaration->Second())
 1287|             m_links->link(m_declaration->Second(), returnType);
 1288| 
 1289|         p = decl;
 1290|         while (p && p->Car()->IsLeaf() && (p->Car()->Eq('*') || p->Car()->Eq('&')))
 1291|             p = Ptree::Rest(p);
 1292|         if (p)
 1293|             // p should now be at the name
 1294|             m_links->link(p->Car(), func);
 1295|     }
 1296|     return 0;
 1297| }
 1298| 
 1299| Ptree*
 1300| SWalker::TranslateVariableDeclarator(Ptree* decl, bool is_const)
 1301| {
 1302|     STrace trace("TranslateVariableDeclarator");
 1303|     // Variable declaration. Restart decoding
 1304|     charencname = decl->GetEncodedName();
 1305|     charenctype = decl->GetEncodedType();
 1306|     m_decoder->init(enctype);
 1307|     // Get type
 1308|     Types::Typetype = m_decoder->decodeType();
 1309|     std::string name;
 1310|     if (m_decoder->isName(encname))
 1311|         name = m_decoder->decodeName(encname);
 1312|     else if (*encname == 'Q')
 1313|     {
 1314|         LOG("Scoped name in variable decl!");
 1315|         nodeLOG(decl);
 1316|         return 0;
 1317|     }
 1318|     else
 1319|     {
 1320|         LOG("Unknown name in variable decl!");
 1321|         nodeLOG(decl);
 1322|         return 0;
 1323|     }
 1324| 
 1325|     // TODO: implement sizes support
 1326|     std::vector<size_tsizes;
 1327|     std::string var_type = m_builder->scope()->type();
 1328|     if (var_type == "class" || var_type == "struct" || var_type == "union")
 1329|         var_type = "data member";
 1330|     else
 1331|     {
 1332|         if (var_type == "function")
 1333|             var_type = "local";
 1334|         var_type += " variable";
 1335|     }
 1336|     AST::Variablevar = m_builder->add_variable(m_linenonametypefalsevar_type);
 1337|     //if (m_declaration->GetComments()) add_comments(var, m_declaration->GetComments());
 1338|     //if (decl->GetComments()) add_comments(var, decl->GetComments());
 1339|     add_comments(varm_declaration);
 1340|     add_comments(var, dynamic_cast<PtreeDeclarator*>(decl));
 1341| 
 1342|     // if storing links, find name
 1343|     if (m_links)
 1344|     {
 1345|         // Do decl type first
 1346|         if (m_store_decl && m_declaration->Second())
 1347|             m_links->link(m_declaration->Second(), type);
 1348| 
 1349|         Ptreep = decl;
 1350|         while (p && p->Car()->IsLeaf() && 
 1351|                 (p->Car()->Eq('*') || p->Car()->Eq('&') || p->Car()->Eq("const")))
 1352|         {
 1353|             // Link the const keyword
 1354|             if (p->Car()->Eq("const"))
 1355|                 m_links->span(p->Car(), "file-keyword");
 1356|             p = Ptree::Rest(p);
 1357|         }
 1358|         if (p)
 1359|         {
 1360|             // p should now be at the name
 1361|             m_links->link(p->Car(), var);
 1362| 
 1363|             // Next might be '=' then expr
 1364|             p = p->Rest();
 1365|             if (p && p->Car() && p->Car()->Eq('='))
 1366|             {
 1367|                 p = p->Rest();
 1368|                 if (p && p->Car())
 1369|                     Translate(p->Car());
 1370|             }
 1371|         }
 1372|     }
 1373|     return 0;
 1374| }
 1375| 
 1376| // Fills the vector of Parameter types by parsing p_params.
 1377| void
 1378| SWalker::TranslateParameters(Ptree* p_params, std::vector<AST::Parameter*>& params)
 1379| {
 1380|     while (p_params)
 1381|     {
 1382|         // A parameter has a type, possibly a name and possibly a value
 1383|         std::string namevalue;
 1384|         AST::Parameter::Mods premodspostmods;
 1385|         if (p_params->Car()->Eq(','))
 1386|             p_params = p_params->Cdr();
 1387|         Ptreeparam = p_params->First();
 1388|         // The type is stored in the encoded type string already
 1389|         Types::Typetype = m_decoder->decodeType();
 1390|         if (!type)
 1391|         {
 1392|             std::cout << "Premature end of decoding!" << std::endl;
 1393|             break// NULL means end of encoding
 1394|         }
 1395|         // Discover contents. Ptree may look like:
 1396|         //[register iostate [* a] = [0 + 2]]
 1397|         //[register iostate [nil] = 0]
 1398|         //[register iostate [nil]]
 1399|         //[iostate [nil] = 0]
 1400|         //[iostate [nil]]   etc
 1401|         if (param->Length() > 1)
 1402|         {
 1403|             // There is a parameter
 1404|             int type_ixvalue_ix = -1len = param->Length();
 1405|             if (len >= 4 && param->Nth(len-2)->Eq('='))
 1406|             {
 1407|                 // There is an =, which must be followed by the value
 1408|                 value_ix = len-1;
 1409|                 type_ix = len-4;
 1410|             }
 1411|             else
 1412|             {
 1413|                 // No =, so last is name and second last is type
 1414|                 type_ix = len-2;
 1415|             }
 1416|             // Link type
 1417|             if (m_links && !param->IsLeaf() && param->Nth(type_ix))
 1418|                 m_links->link(param->Nth(type_ix), type);
 1419|             // Skip keywords (eg: register) which are Leaves
 1420|             for (int ix = 0ix < type_ix && param->Nth(ix)->IsLeaf(); ix++)
 1421|             {
 1422|                 Ptreeleaf = param->Nth(ix);
 1423|                 premods.push_back(parse_name(leaf));
 1424|             }
 1425|             // Find name
 1426|             if (Ptreepname = param->Nth(type_ix+1))
 1427|             {
 1428|                 if (pname->Last() && !pname->Last()->IsLeaf() && pname->Last()->First() &&
 1429|                         pname->Last()->First()->Eq(')') && pname->Length() >= 4)
 1430|                 {
 1431|                     // Probably a function pointer type
 1432|                     // pname is [* [( [* convert] )] ( [params] )]
 1433|                     // set to [( [* convert] )] from example
 1434|                     pname = pname->Nth(pname->Length() - 4);
 1435|                     if (pname && !pname->IsLeaf() && pname->Length() == 3)
 1436|                     {
 1437|                         // set to [* convert] from example
 1438|                         pname = pname->Second();
 1439|                         if (pname && pname->Second() && pname->Second()->IsLeaf())
 1440|                             name = parse_name(pname->Second());
 1441|                     }
 1442|                 }
 1443|                 else if (!pname->IsLeaf() && pname->Last() && pname->Last()->Car())
 1444|                 {
 1445|                     // * and & modifiers are stored with the name so we must skip them
 1446|                     Ptreelast = pname->Last()->Car();
 1447|                     if (!last->Eq('*') && !last->Eq('&'))
 1448|                         // The last node is the name:
 1449|                         name = last->ToString();
 1450|                 }
 1451|             }
 1452|             // Find value
 1453|             if (value_ix >= 0)
 1454|                 value = param->Nth(value_ix)->ToString();
 1455|         }
 1456|         // Add the AST.Parameter type to the list
 1457|         params.push_back(new AST::Parameter(premods, type, postmods, name, value));
 1458|         p_params = Ptree::Rest(p_params);
 1459|     }
 1460| }
 1461| 
 1462| void SWalker::TranslateFunctionName(char* encname, std::string& realname, Types::Type*& returnType)
 1463| {
 1464|     STrace trace("SWalker::TranslateFunctionName");
 1465|     if (m_decoder->isName(encname))
 1466|     {
 1467|         if (encname[1] == '@')
 1468|         {
 1469|             // conversion operator
 1470|             m_decoder->init(encname);
 1471|             m_decoder->iter() += 2;
 1472|             returnType = m_decoder->decodeType();
 1473|             realname = "("+m_type_formatter->format(returnType)+")";
 1474|         }
 1475|         else
 1476|         {
 1477|             // simple name
 1478|             realname = m_decoder->decodeName(encname);
 1479|             // operator names are missing the 'operator', add it back
 1480|             char c = realname[0];
 1481|             if (c == '+' || c == '-' || c == '*' || c == '/' || c == '%'
 1482|                     || c == '^' || c == '&' || c == '!' || c == '=' || c == '<'
 1483|                     || c == '>' || c == ',' || c == '(' || c == '['
 1484|                     || (c == '~' && realname[1] == 0))
 1485|                 realname = "operator"+realname;
 1486|         }
 1487|     }
 1488|     else if (*encname == 'Q')
 1489|     {
 1490|         // If a function declaration has a scoped name, then it is not
 1491|         // declaring a new function in that scope and can be ignored in
 1492|         // the context of synopsis.
 1493|         // TODO: maybe needed for syntax stuff?
 1494|         return;
 1495|     }
 1496|     else if (*encname == 'T')
 1497|     {
 1498|         // Template specialisation.
 1499|         // blah<int, int> is T4blah2ii ---> realname = foo<int,int>
 1500|         m_decoder->init(encname);
 1501|         code_iteriter = ++m_decoder->iter();
 1502|         realname = m_decoder->decodeName()+"<";
 1503|         code_iter tend = iter + (*iter - 0x80u);
 1504|         iter++; // For some reason, putting this in prev line causes error with 3.2
 1505|         bool first = true;
 1506|         // Append type names to realname
 1507|         while (iter <= tend)
 1508|         {
 1509|             /*Types::Type* type = */m_decoder->decodeType();
 1510|             if (!first)
 1511|                 realname+=",";
 1512|             else
 1513|                 first=false;
 1514|             realname += "type"//type->ToString();
 1515|         }
 1516|         realname += ">";
 1517|     }
 1518|     else
 1519|         std::cout << "Warning: Unknown function name: " << encname << std::endl;
 1520| }
 1521| 
 1522| //. Class or Enum
 1523| Ptree*
 1524| SWalker::TranslateTypespecifier(Ptree* tspec)
 1525| {
 1526|     STrace trace("SWalker::TranslateTypespecifier");
 1527|     Ptree *class_spec = GetClassOrEnumSpec(tspec);
 1528|     if (class_spec)
 1529|         Translate(class_spec);
 1530|     return 0;
 1531| }
 1532| 
 1533| Ptree*
 1534| SWalker::TranslateTypedef(Ptree* node)
 1535| {
 1536|     STrace trace("SWalker::TranslateTypedef");
 1537|     if (m_links)
 1538|         m_links->span(node->First(), "file-keyword");
 1539|     /* Ptree *tspec = */
 1540|     TranslateTypespecifier(node->Second());
 1541|     m_declaration = node;
 1542|     m_store_decl = true;
 1543|     for (Ptree *declarator = node->Third(); declaratordeclarator = declarator->ListTail(2))
 1544|         TranslateTypedefDeclarator(declarator->Car());
 1545|     return 0;
 1546| }
 1547| 
 1548| void SWalker::TranslateTypedefDeclarator(Ptree* node)
 1549| {
 1550|     if (node->What() != ntDeclarator)
 1551|         return;
 1552|     charencname = node->GetEncodedName();
 1553|     charenctype = node->GetEncodedType();
 1554|     if (!encname || !enctype)
 1555|         return;
 1556| 
 1557|     update_line_number(node);
 1558| 
 1559|     // Get type of declarator
 1560|     m_decoder->init(enctype);
 1561|     Types::Typetype = m_decoder->decodeType();
 1562|     // Get name of typedef
 1563|     std::string name = m_decoder->decodeName(encname);
 1564|     // Create typedef object
 1565|     AST::Typedeftdef = m_builder->add_typedef(m_linenonametypefalse);
 1566|     add_comments(tdef, dynamic_cast<PtreeDeclarator*>(node));
 1567| 
 1568|     // if storing links, find name
 1569|     if (m_links)
 1570|     {
 1571|         if (m_store_decl && m_declaration->Second())
 1572|             m_links->link(m_declaration->Second(), type);
 1573|         Ptreep = node;
 1574|         while (p && p->Car()->IsLeaf() && (p->Car()->Eq('*') || p->Car()->Eq('&')))
 1575|             p = Ptree::Rest(p);
 1576|         if (p)
 1577|             // p should now be at the name
 1578|             m_links->link(p->Car(), tdef);
 1579|     }
 1580| }
 1581| 
 1582| Ptree*
 1583| SWalker::TranslateFunctionImplementation(Ptree* node)
 1584| {
 1585|     STrace trace("SWalker::TranslateFunctionImplementation");
 1586|     m_function = 0;
 1587|     m_params.clear();
 1588|     TranslateDeclarator(node->Third());
 1589|     if (!m_filter->should_visit_function_impl(m_file))
 1590|         return 0;
 1591|     if (!m_function)
 1592|     {
 1593|         std::cerr << "Warning: function was null!" << std::endl;
 1594|         return 0;
 1595|     }
 1596| 
 1597|     FuncImplCache cache;
 1598|     cache.func = m_function;
 1599|     cache.params = m_param_cache;
 1600|     cache.body = node->Nth(3);
 1601| 
 1602|     if (dynamic_cast<AST::Class*>(m_builder->scope()))
 1603|         m_func_impl_stack.back().push_back(cache);
 1604|     else
 1605|         TranslateFuncImplCache(cache);
 1606|     return 0;
 1607| }
 1608| 
 1609| void
 1610| SWalker::TranslateFuncImplCache(const FuncImplCache& cache)
 1611| {
 1612|     STrace trace("SWalker::TranslateFuncImplCache");
 1613|     // We create a dummy namespace with the name of the function. Any
 1614|     // declarations in the function are added to this dummy namespace. Once we
 1615|     // are done, we remove it from the parent scope (its not much use in the
 1616|     // documents)
 1617|     std::vector<std::string> name = cache.func->name();
 1618|     name.back() = "`"+name.back();
 1619|     m_builder->start_function_impl(name);
 1620|     try
 1621|     {
 1622|         // Add parameters
 1623|         std::vector<AST::Parameter*>::const_iterator iter, end;
 1624|         iter = cache.params.begin();
 1625|         end = cache.params.end();
 1626|         while (iter != end)
 1627|         {
 1628|             AST::Parameter* param = *iter++;
 1629|             // Make sure the parameter is named
 1630|             if (param->name().size())
 1631|                 m_builder->add_variable(m_lineno, param->name(), param->type(), false, "parameter");
 1632|         }
 1633|         // Add 'this' if method
 1634|         m_builder->add_this_variable();
 1635|         // Translate the function body
 1636|         TranslateBlock(cache.body);
 1637|     }
 1638|     catch (...)
 1639|     {
 1640|         LOG("Cleaning up func impl cache");
 1641|         m_builder->end_function_impl();
 1642|         throw;
 1643|     }
 1644|     m_builder->end_function_impl();
 1645| }
 1646| 
 1647| Ptree*
 1648| SWalker::TranslateAccessSpec(Ptree* spec)
 1649| {
 1650|     STrace trace("SWalker::TranslateAccessSpec");
 1651|     AST::Access axs = AST::Default;
 1652|     switch (spec->First()->What())
 1653|     {
 1654|     case PUBLIC:
 1655|         axs = AST::Public;
 1656|         break;
 1657|     case PROTECTED:
 1658|         axs = AST::Protected;
 1659|         break;
 1660|     case PRIVATE:
 1661|         axs = AST::Private;
 1662|         break;
 1663|     }
 1664|     m_builder->set_access(axs);
 1665|     if (m_links)
 1666|         m_links->span(spec->First(), "file-keyword");
 1667|     return 0;
 1668| }
 1669| 
 1670| /* Enum Spec
 1671|  *  [ enum [name] [{ [name [= value] ]* }] ]
 1672|  */
 1673| Ptree*
 1674| SWalker::TranslateEnumSpec(Ptree *spec)
 1675| {
 1676|     //update_line_number(spec);
 1677|     if (m_links)
 1678|         m_links->span(spec->First(), "file-keyword");
 1679|     if (!spec->Second())
 1680|     {
 1681|         return 0/* anonymous enum */
 1682|     }
 1683|     std::string name = spec->Second()->ToString();
 1684| 
 1685|     update_line_number(spec);
 1686|     int enum_lineno = m_lineno;
 1687|     // Parse enumerators
 1688|     std::vector<AST::Enumerator*> enumerators;
 1689|     Ptreepenum = spec->Third()->Second();
 1690|     AST::Enumeratorenumor;
 1691|     while (penum)
 1692|     {
 1693|         update_line_number(penum);
 1694|         Ptreepenumor = penum->First();
 1695|         if (penumor->IsLeaf())
 1696|         {
 1697|             // Just a name
 1698|             enumor = m_builder->add_enumerator(m_linenopenumor->ToString(), "");
 1699|             add_comments(enumor, static_cast<CommentedLeaf*>(penumor)->GetComments());
 1700|             if (m_linksm_links->link(penumorenumor);
 1701|         }
 1702|         else
 1703|         {
 1704|             // Name = Value
 1705|             std::string name = penumor->First()->ToString(), value;
 1706|             if (penumor->Length() == 3)
 1707|                 value = penumor->Third()->ToString();
 1708|             enumor = m_builder->add_enumerator(m_linenonamevalue);
 1709|             add_comments(enumor, dynamic_cast<CommentedLeaf*>(penumor->First()));
 1710|             if (m_linksm_links->link(penumor->First()
 1711|                                            enumor);
 1712|         }
 1713|         enumerators.push_back(enumor);
 1714|         penum = Ptree::Rest(penum);
 1715|         // Skip comma
 1716|         if (penum && penum->Car() && penum->Car()->Eq(','))
 1717|             penum = Ptree::Rest(penum);
 1718|     }
 1719|     if (m_extract_tails)
 1720|     {
 1721|         Ptreeclose = spec->Third()->Third();
 1722|         enumor = new AST::Enumerator(m_file, m_lineno, "dummy", m_dummyname, "");
 1723|         add_comments(enumor, static_cast<CommentedLeaf*>(close));
 1724|         enumerators.push_back(enumor);
 1725|     }
 1726| 
 1727|     // Create AST.Enum object
 1728|     AST::EnumtheEnum = m_builder->add_enum(enum_lineno,name,enumerators);
 1729|     add_comments(theEnumm_declaration);
 1730|     if (m_declaration)
 1731|     {
 1732|         // Enum declared inside declaration. Comments for the declaration
 1733|         // belong to the enum. This is policy. #TODO review policy
 1734|         //m_declaration->SetComments(nil); ?? typedef doesn't have comments?
 1735|     }
 1736|     if (m_links)
 1737|         m_links->link(spec->Second(), theEnum);
 1738|     return 0;
 1739| }
 1740| 
 1741| 
 1742| Ptree*
 1743| SWalker::TranslateUsing(Ptree* node)
 1744| {
 1745|     STrace trace("SWalker::TranslateUsing");
 1746|     // [ using Foo :: x ; ]
 1747|     // [ using namespace Foo ; ]
 1748|     // [ using namespace Foo = Bar ; ]
 1749|     if (m_links)
 1750|         m_links->span(node->First(), "file-keyword");
 1751|     bool is_namespace = false;
 1752|     Ptree *p = node->Rest();
 1753|     if (p->First()->Eq("namespace"))
 1754|     {
 1755|         if (m_links)
 1756|             m_links->span(p->First(), "file-keyword");
 1757|         // Find namespace to alias
 1758|         p = p->Rest();
 1759|         is_namespace = true;
 1760|     }
 1761|     // Find name that we are looking up, and make a new ptree list for linking it
 1762|     Ptree *p_name = Ptree::Snoc(nil, p->Car());
 1763|     ScopedName name;
 1764|     if (p->First()->Eq("::"))
 1765|         // Eg; "using ::memcpy;" Indicate global scope with empty first
 1766|         name.push_back("");
 1767|     else
 1768|     {
 1769|         name.push_back(parse_name(p->First()));
 1770|         p = p->Rest();
 1771|     }
 1772|     while (p->First()->Eq("::"))
 1773|     {
 1774|         p_name = Ptree::Snoc(p_namep->Car()); // Add '::' to p_name
 1775|         p = p->Rest();
 1776|         name.push_back(parse_name(p->First()));
 1777|         p_name = Ptree::Snoc(p_namep->Car()); // Add identifier to p_name
 1778|         p = p->Rest();
 1779|     }
 1780|     // Resolve and link name
 1781|     try
 1782|     {
 1783|         Types::Namedtype = m_lookup->lookupType(name);
 1784|         if (m_links)
 1785|             m_links->link(p_nametype);
 1786|         if (is_namespace)
 1787|         {
 1788|             // Check for '=' alias
 1789|             if (p->First()->Eq("="))
 1790|             {
 1791|                 p = p->Rest();
 1792|                 std::string alias = parse_name(p->First());
 1793|                 m_builder->add_aliased_using_namespace(typealias);
 1794|             }
 1795|             else
 1796|                 m_builder->add_using_namespace(type);
 1797|         }
 1798|         else
 1799|             // Let builder do all the work
 1800|             m_builder->add_using_declaration(type);
 1801|     }
 1802|     catch (const TranslateError& e)
 1803|     {
 1804|         LOG("Oops!");
 1805|         e.set_node(node);
 1806|         throw;
 1807|     }
 1808|     return 0;
 1809| }
 1810| 
 1811| 
 1812| // vim: set ts=8 sts=4 sw=4 et: