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|
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| char* fname;
218| int fname_len;
219| m_lineno = m_parser->LineNumber(ptree->LeftMost(), fname, fname_len);
220| if (fname != m_filename_ptr)
221| {
222| m_filename_ptr = fname;
223| m_file = m_filter->get_sourcefile(fname, fname_len);
224| m_builder->set_file(m_file);
225| }
226| }
227|
228| AST::Comment* make_Comment(SourceFile* file, int line, Ptree* first, bool suspect=false)
229| {
230| return new AST::Comment(file, line, first->ToString(), suspect);
231| }
232| Leaf* make_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 (Ptree* next = node->Rest(); node && !node->IsLeaf(); next = node->Rest())
252| {
253| Ptree* first = 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| char* next_pos = next->First()->GetPosition();
277| char* start_pos = node->First()->GetPosition();
278| char* curr_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_pos, len));
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| char* pos = 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|
330| AST::Comment* comment = make_Comment(m_file, 0, first, suspect);
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(decl, node->GetComments());
357| }
358| void SWalker::add_comments(AST::Declaration* decl, PtreeDeclaration* node)
359| {
360| if (node)
361| add_comments(decl, node->GetComments());
362| }
363| void SWalker::add_comments(AST::Declaration* decl, PtreeDeclarator* node)
364| {
365| if (node)
366| add_comments(decl, node->GetComments());
367| }
368| void SWalker::add_comments(AST::Declaration* decl, PtreeNamespaceSpec* node)
369| {
370| if (node)
371| add_comments(decl, node->GetComments());
372| }
373| void SWalker::find_comments(Ptree* node)
374| {
375| Ptree* leaf, *parent;
376| leaf = FindLeftLeaf(node, parent);
377| if (leaf)
378| add_comments(NULL, dynamic_cast<CommentedLeaf*>(leaf));
379| }
380|
381| Ptree* SWalker::TranslateArgDeclList(bool, Ptree*, Ptree*)
382| {
383| STrace trace("SWalker::TranslateArgDeclList NYI");
384| return 0;
385| }
386| Ptree* SWalker::TranslateInitializeArgs(PtreeDeclarator*, Ptree*)
387| {
388| STrace trace("SWalker::TranslateInitializeArgs NYI");
389| return 0;
390| }
391| Ptree* SWalker::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|
474|
475| }
476| catch (const std::exception& e)
477| {
478| std::cout << "Warning: An exception occurred: " << e.what() << std::endl;
479| std::cout << "At: ";
480| char* fname;
481| int fname_len;
482| int lineno = m_parser->LineNumber(node->LeftMost(), fname, fname_len);
483| std::cout << " (" << std::string(fname, fname_len) << ":" << lineno << ")" << std::endl;
484| }
485| catch (...)
486| {
487| std::cout << "Warning: An unknown exception occurred: " << std::endl;
488| std::cout << "At: ";
489| char* fname;
490| int fname_len;
491| int lineno = m_parser->LineNumber(node->LeftMost(), fname, fname_len);
492| std::cout << " (" << std::string(fname, fname_len) << ":" << lineno << ")" << std::endl;
493| }
494| #endif
495| }
496|
497| // Default translate, usually means a literal
498| Ptree* SWalker::TranslatePtree(Ptree* node)
499| {
500| // Determine type of node
501| char* str = 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 char* num_type = (*str == '.' ? "double" : "int");
509| while (*++str)
510| {
511| if (*str >= '0' && *str <= '9')
512| ;
513| else if (*str == 'e' || *str == 'E')
514| {
515|
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|
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 pre, post;
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|
576| AST::Declaration* decl;
577| update_line_number(node);
578| decl = m_builder->add_tail_comment(m_lineno);
579| add_comments(decl, node);
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| Ptree* pNamespace = def->First();
603| Ptree* pIdentifier = def->Second();
604| Ptree* pBody = def->Third();
605|
606| if (m_links)
607| m_links->span(pNamespace, "file-keyword");
608| else
609| update_line_number(def);
610|
611|
612| AST::Namespace* ns;
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(pIdentifier, ns);
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();
643|
644| std::vector<std::string> attributes(node->Car()->Length() - 1);
645| for (int i = 0; i != 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|
652| Ptree* name = 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|
662| ScopedName uname;
663| uname.push_back(parse_name(name));
664| type = new Types::Unknown(uname);
665| }
666| }
667| else
668| {
669| char* encname = name->GetEncodedName();
670| m_decoder->init(encname);
671| type = m_decoder->decodeType();
672| }
673| if (m_links)
674| m_links->link(name, type);
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|
688| STrace trace("SWalker::TranslateClassSpec");
689| enum { SizeForwardDecl = 2, SizeAnonClass = 3, SizeClass = 4 };
690|
691| AST::Parameter::vector* is_template = m_template;
692| m_template = NULL;
693|
694| int size = Ptree::Length(node);
695|
696| if (size == SizeForwardDecl)
697| {
698|
699|
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_lineno, name, is_template);
704| if (m_links)
705| {
706| PtreeClassSpec* cspec = static_cast<PtreeClassSpec*>(node);
707| add_comments(NULL, cspec->GetComments());
708| }
709| return 0;
710| }
711| Ptree* pClass = node->First();
712| Ptree* pName = NULL, *pInheritance = NULL;
713| Ptree* pBody = 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|
735| AST::Class *clas;
736| std::string type = parse_name(pClass);
737| char* encname = 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::Parameterized* param = 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 = 0; i < param->parameters().size(); i++)
752| if (Types::Dependent* dep = dynamic_cast<Types::Dependent*>(param->parameters()[i])
753| )
754| {
755| if (dep->name().size() == 1 && dep->name()[0] == "*")
756| {
757|
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_lineno, type, name, is_template);
767|
768|
769| }
770| else if (encname[0] == 'Q')
771| {
772| ScopedName names;
773| m_decoder->decodeQualName(names);
774| clas = m_builder->start_class(m_lineno, type, names);
775| }
776| else
777| {
778| std::string name = m_decoder->decodeName();
779| clas = m_builder->start_class(m_lineno, type, name, is_template);
780| }
781| if (m_links && pName)
782| m_links->link(pName, clas);
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|
793| PtreeClassSpec* cspec = static_cast<PtreeClassSpec*>(node);
794| add_comments(clas, cspec->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|
803| FuncImplVec& vec = 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::vector* old_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::vector* old_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| Ptree* rest = Ptree::Second(block);
962| while (rest != nil)
963| {
964| Translate(rest->Car());
965| rest = rest->Cdr();
966| }
967| if (m_extract_tails)
968| {
969| Ptree* close = Ptree::Third(block);
970| AST::Declaration* decl;
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| Ptree* rest = Ptree::Second(brace);
985| while (rest != nil)
986| {
987| Translate(rest->Car());
988| rest = rest->Cdr();
989| }
990| if (m_extract_tails)
991| {
992| Ptree* close = Ptree::Third(brace);
993| AST::Declaration* decl;
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| Ptree* body = Ptree::Nth(def, 4);
1008| Ptree* class_spec = GetClassTemplateSpec(body);
1009| if(class_spec->IsA(ntClassSpec))
1010| TranslateTemplateClass(def, class_spec);
1011| else
1012| TranslateTemplateFunction(def, body);
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| Ptree* SWalker::TranslateTypeof(Ptree* spec, Ptree* declarations)
1021| {
1022| STrace trace("SWalker::TranslateTypeof");
1023| nodeLOG(spec);
1024| char* encname = 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::Type* type = m_lookup->lookupType(name, true);
1037|
1038| Types::Declared* declared = dynamic_cast<Types::Declared*>(type);
1039| if (!declared)
1040| return 0;
1041| LOG("Looked up " << declared->name());
1042| AST::Declaration* decl = 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| Ptree* declarator = 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| Ptree* SWalker::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| Ptree* decls = 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 char* encoded_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| Ptree* rest = 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|
1157| STrace trace("SWalker::TranslateDeclarator");
1158| // Insert code from occ.cc here
1159| char* encname = decl->GetEncodedName();
1160| char* enctype = 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_iter& iter = 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(decl, is_const);
1180| else
1181| return TranslateVariableDeclarator(decl, is_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::vector* is_template = m_template;
1197| m_template = NULL;
1198|
1199| code_iter& iter = m_decoder->iter();
1200| char* encname = decl->GetEncodedName();
1201|
1202|
1203| ++iter;
1204|
1205|
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| ;
1221| Types::Type* returnType = m_decoder->decodeType();
1222|
1223|
1224| std::vector<std::string> premod;
1225| Ptree* p = Ptree::First(m_declaration);
1226| while (p)
1227| {
1228| premod.push_back(p->ToString());
1229| p = Ptree::Rest(p);
1230| }
1231|
1232| AST::Function* func = 0;
1233| // Find name:
1234| if (encname[0] == 'Q')
1235| {
1236|
1237| std::vector<std::string> names;
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::Named* named_type = m_lookup->lookupType(names, true);
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|
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::Parameter* param = *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|
1265| std::string realname;
1266| TranslateFunctionName(encname, realname, returnType);
1267|
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_lineno, name, premod, returnType, realname, is_template);
1274| func->parameters() = params;
1275| }
1276| add_comments(func, m_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| char* encname = decl->GetEncodedName();
1305| char* enctype = decl->GetEncodedType();
1306| m_decoder->init(enctype);
1307|
1308| Types::Type* type = 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|
1326| std::vector<size_t> sizes;
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::Variable* var = m_builder->add_variable(m_lineno, name, type, false, var_type);
1337| //if (m_declaration->GetComments()) add_comments(var, m_declaration->GetComments());
1338| //if (decl->GetComments()) add_comments(var, decl->GetComments());
1339| add_comments(var, m_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| Ptree* p = 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|
1383| std::string name, value;
1384| AST::Parameter::Mods premods, postmods;
1385| if (p_params->Car()->Eq(','))
1386| p_params = p_params->Cdr();
1387| Ptree* param = p_params->First();
1388|
1389| Types::Type* type = m_decoder->decodeType();
1390| if (!type)
1391| {
1392| std::cout << "Premature end of decoding!" << std::endl;
1393| break;
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_ix, value_ix = -1, len = 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 = 0; ix < type_ix && param->Nth(ix)->IsLeaf(); ix++)
1421| {
1422| Ptree* leaf = param->Nth(ix);
1423| premods.push_back(parse_name(leaf));
1424| }
1425| // Find name
1426| if (Ptree* pname = 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|
1446| Ptree* last = 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_iter& iter = ++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";
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(); declarator; declarator = 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| char* encname = node->GetEncodedName();
1553| char* enctype = 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::Type* type = m_decoder->decodeType();
1562|
1563| std::string name = m_decoder->decodeName(encname);
1564|
1565| AST::Typedef* tdef = m_builder->add_typedef(m_lineno, name, type, false);
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| Ptree* p = 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;
1682| }
1683| std::string name = spec->Second()->ToString();
1684|
1685| update_line_number(spec);
1686| int enum_lineno = m_lineno;
1687|
1688| std::vector<AST::Enumerator*> enumerators;
1689| Ptree* penum = spec->Third()->Second();
1690| AST::Enumerator* enumor;
1691| while (penum)
1692| {
1693| update_line_number(penum);
1694| Ptree* penumor = penum->First();
1695| if (penumor->IsLeaf())
1696| {
1697| // Just a name
1698| enumor = m_builder->add_enumerator(m_lineno, penumor->ToString(), "");
1699| add_comments(enumor, static_cast<CommentedLeaf*>(penumor)->GetComments());
1700| if (m_links) m_links->link(penumor, enumor);
1701| }
1702| else
1703| {
1704|
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_lineno, name, value);
1709| add_comments(enumor, dynamic_cast<CommentedLeaf*>(penumor->First()));
1710| if (m_links) m_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| Ptree* close = 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|
1728| AST::Enum* theEnum = m_builder->add_enum(enum_lineno,name,enumerators);
1729| add_comments(theEnum, m_declaration);
1730| if (m_declaration)
1731| {
1732|
1733|
1734|
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|
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_name, p->Car()); // Add '::' to p_name
1775| p = p->Rest();
1776| name.push_back(parse_name(p->First()));
1777| p_name = Ptree::Snoc(p_name, p->Car()); // Add identifier to p_name
1778| p = p->Rest();
1779| }
1780| // Resolve and link name
1781| try
1782| {
1783| Types::Named* type = m_lookup->lookupType(name);
1784| if (m_links)
1785| m_links->link(p_name, type);
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(type, alias);
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|