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