From: <net...@us...> - 2003-04-29 09:55:42
|
Update of /cvsroot/cpptool/rfta/src/rftaparser In directory sc8-pr-cvs1:/tmp/cvs-serv29065/src/rftaparser Added Files: DeclarationDetailsParser.h DeclarationDetailsParser.cpp Log Message: -- corrected "UnparsedDeclarationMutator" to be a real Mutator that can be used by MaxLODMutator --- NEW FILE: DeclarationDetailsParser.h --- // ////////////////////////////////////////////////////////////////////////// // Header file DeclarationDetailsParser.h for class DeclarationDetailsParser // (c)Copyright 2003, Andre Baresel. // Created: 2003/04/18 // ////////////////////////////////////////////////////////////////////////// #ifndef RFTA_DeclarationDetailsParser_H #define RFTA_DeclarationDetailsParser_H #include <rfta/parser/Parser.h> #include <set> namespace Refactoring { /// Mutate an unparsed-declaration-list into a parsed declaration-list class DeclarationDetailsParser : public Parser { public: /*! Constructs a DeclarationDetailsParser object. * * source range must not start with white spaces. */ DeclarationDetailsParser( ParseContext &context, const ASTNodePtr &node, const SourceASTNodePtr &sourceNode); /// Destructor. virtual ~DeclarationDetailsParser(); bool tryParse(); private: // // private methods for type specifier parsing: // // ENTRY-Point: void parseDeclarationSpecifierList(ASTNodePtr &specifierList); // parsing of composed specifiers (e.g. "class x { ... }" void parseComposedSpecifier(int specifierStart, std::string& specifierIdent, ASTNodePtr &specifierList); /** * function does try to read a user defined type (it checks for a variable * declaration) * returns false in case of the end of specifier list */ bool tryParseUserDefinedType(std::string& typename_); void readNestedName(std::string& nestedname); void readClassOrEnumSpecifier(ASTNodePtr& specifier, std::string keyword, std::string name); // // private methods for declarator parsing: // // ENTRY-Point: void parseDeclarators(); // parser has to stay at the character after the operator keyword... void parseOperator(int declaratorStartIndex); bool tryReadToken(std::string& token); bool doesKeywordFollow( std::string keyword ); static bool tryFindNextBalanced( const char *¤t, const char *end, char opening = '<', char closing = '>' ); bool skipOverAssignmentInitializer(); void createAndAddInitializerNode( const ASTNodePtr &variableDeclNode ); void addValueNode( const ASTNodePtr& variableDeclNode, int start, int end ) const; void addInitializerNode( const ASTNodePtr& variableDeclNode, const ASTNodeType initializerType, int initializerStartIndex ) const; static bool isOperatorIdentifier(std::string name); private: ASTNodePtr node_; typedef std::set<std::string> KeywordSet; KeywordSet declarationSpecifiers; KeywordSet elaboratedSpecifiers; }; // Inlines methods for DeclarationDetailsParser: // -------------------------------------------- } // namespace Refactoring #endif // RFTA_DeclarationDetailsParser_H --- NEW FILE: DeclarationDetailsParser.cpp --- // ////////////////////////////////////////////////////////////////////////// // Implementation file DeclarationDetailsParser.cpp for class DeclarationDetailsParser // (c)Copyright 2003, Andre Baresel. // Created: 2003/04/18 // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "DeclarationDetailsParser.h" #include <rfta/parser/ASTNodes.h> #include <rfta/parser/ParseContext.h> #include <rfta/parser/DeclarationListParser.h> namespace Refactoring { DeclarationDetailsParser::DeclarationDetailsParser( ParseContext &context, const ASTNodePtr &node, const SourceASTNodePtr &sourceNode) : Parser( context, sourceNode->getBlankedSourceStart() + node->getRange().getStartIndex(), sourceNode->getBlankedSourceStart() + node->getRange().getEndIndex() ) , node_( node ) { // build lookup table for specifiers: // generel specifier: declarationSpecifiers.insert("typedef"); declarationSpecifiers.insert("friend"); // storage class declarationSpecifiers.insert("auto"); declarationSpecifiers.insert("register"); declarationSpecifiers.insert("static"); declarationSpecifiers.insert("extern"); declarationSpecifiers.insert("mutable"); // function specifiers declarationSpecifiers.insert("inline"); declarationSpecifiers.insert("virtual"); declarationSpecifiers.insert("explicit"); // simple type specifiers declarationSpecifiers.insert("char"); declarationSpecifiers.insert("wchar_t"); declarationSpecifiers.insert("bool"); declarationSpecifiers.insert("short"); declarationSpecifiers.insert("int"); declarationSpecifiers.insert("long"); declarationSpecifiers.insert("signed"); declarationSpecifiers.insert("unsigned"); declarationSpecifiers.insert("float"); declarationSpecifiers.insert("double"); declarationSpecifiers.insert("void"); // cv-qualifier declarationSpecifiers.insert("const"); declarationSpecifiers.insert("volatile"); // build lookup table for elaborated specifiers: elaboratedSpecifiers.insert("class"); elaboratedSpecifiers.insert("struct"); elaboratedSpecifiers.insert("enum"); elaboratedSpecifiers.insert("union"); elaboratedSpecifiers.insert("typename"); } DeclarationDetailsParser::~DeclarationDetailsParser() { } bool DeclarationDetailsParser::tryParse() { ASTNodePtr declarationNode = node_; node_->mutateType( ASTNodeTypes::declaration ); ASTNodePtr specifierList = createASTNode( ASTNodeTypes::declarationSpecifierList, declarationNode, getCurrentIndex(), getCurrentLength() ); declarationNode->setPropertyNode( ASTNodeProperties::declarationSpecifiersProperty, specifierList ); // read the declaration specifier list and add childs to property: parseDeclarationSpecifierList(specifierList); backtrackSkippingSpaces(); specifierList->setLength(getCurrentLength()); skipSpaces(); // check if declaration has also a declarator: if (!tryNextIs(';')) { // read all declarators and add childs to property: parseDeclarators(); } // return with no parsing error: return true; } /** * function parses all declaration specifiers until the first declarator is found. * the decision about the end of the specifier list is done in "tryParseUserDefinedType" */ void DeclarationDetailsParser::parseDeclarationSpecifierList(ASTNodePtr &specifierList) { std::string identifier; const char * save_pointer = getCurrent(); int lastIndex; while ( save_pointer = getCurrent(),lastIndex=getCurrentIndex(), tryReadNextIdentifier(identifier) ) { if (declarationSpecifiers.find(identifier) != declarationSpecifiers.end()) { // add the specifier node ASTNodePtr specifier = createASTNode( ASTNodeTypes::simpleTypeSpecifier, specifierList, lastIndex, getCurrentIndex()-lastIndex ); specifierList->addChild(specifier); skipSpaces(); continue; } // check elaborated-specifiers: else if (elaboratedSpecifiers.find(identifier) != elaboratedSpecifiers.end()) { skipSpaces(); parseComposedSpecifier(lastIndex, identifier, specifierList); skipSpaces(); continue; } else // check characters after symbol to find out if it's a userdefined type... if (tryParseUserDefinedType(identifier)) { backtrackSkippingSpaces(); // add the specifier node ASTNodePtr specifier = createASTNode( ASTNodeTypes::simpleTypeSpecifier, specifierList, lastIndex, getCurrentIndex()-lastIndex ); specifierList->addChild(specifier); skipSpaces(); continue; } else { current_ = save_pointer; break; } } } /** * function tries to parse elaborated and class/enum/struct/union specifiers * a decision about the type is found during parsing. */ void DeclarationDetailsParser::parseComposedSpecifier( int specifierStart, std::string& specifierIdent, ASTNodePtr &specifierList) { // CASE 1: // check if identifier starts with a '::') // (definitions can not start with nested names -> this declaration is an elaborated type // which ends after the name) if (tryNextIs(':')) { if (!tryNextIs(':')) { throwFailure( "Expected a double colon => '::'." ); } skipSpaces(); // read the full name: std::string name("::"); readNestedName(name); // add the specifier node ASTNodePtr specifier = createASTNode( ASTNodeTypes::elaboratedTypeSpecifier, specifierList, specifierStart, getCurrentIndex()-specifierStart ); specifierList->addChild(specifier); return; // FINISH HERE } // try to read the identifier that can be specifier after an elaborated type specifier // if no identifier follows, an unnamed type is specifier (e.g. "struct { } x;") std::string secondIdent; if (tryReadNextIdentifier(secondIdent)) { skipSpaces(); } // check if no identifier or the identifier is not followed by a ':' (e.g. "class x {" if (secondIdent.empty() || !tryNextIs(':')) { // add the specifier node ASTNodePtr specifier = createASTNode( ASTNodeTypes::classSpecifier, specifierList, specifierStart, getCurrentIndex()-specifierStart ); specifierList->addChild(specifier); readClassOrEnumSpecifier(specifier, specifierIdent, secondIdent); // set real length after completed parsing specifier->setLength(getCurrentIndex()-specifierStart); return; } // HERE we come only in case where the type is followed by a colon. "e.g. class x:" // check if it is only a single colon (which means inheritance information e.g. "class x: public y ") if (!tryNextIs(':')) { // yes it's - so parse the class specifier if (specifierIdent == "class" || specifierIdent == "struct" || specifierIdent == "union") { // add the specifier node ASTNodePtr specifier = createASTNode( ASTNodeTypes::classSpecifier, specifierList, specifierStart, getCurrentIndex()-specifierStart ); specifierList->addChild(specifier); // read the complete specifier: readClassOrEnumSpecifier(specifier, specifierIdent, secondIdent); // set real length after completed parsing specifier->setLength(getCurrentIndex()-specifierStart); return; // FINISH HERE (the class specifier ends here !) } throwFailure( "Expected a double colon => '::'." ); } // HERE we come only in case of a double colon after the identifier which means: // an elaborated type is specified: e.g. "class x::y" skipSpaces(); // read the full name: secondIdent.append("::"); readNestedName(secondIdent); // add the specifier node ASTNodePtr specifier = createASTNode( ASTNodeTypes::elaboratedTypeSpecifier, specifierList, specifierStart, getCurrentIndex()-specifierStart ); specifierList->addChild(specifier); // set real length after completed parsing specifier->setLength(getCurrentIndex()-specifierStart); } bool DeclarationDetailsParser::tryParseUserDefinedType(std::string& typename_) { // the 'typename_' might be a userdefined type or a declarator // here we try to find out: if (typename_ == "operator") return false; // first read the fully qualified name: skipSpaces(); // maybe a full qualified typename (e.g. "std::string") if (tryNextIs(':')) { if (!tryNextIs(':')) { --current_; return false; // it's not "::" - might be the bitfield operator (e.g. "int myvar:0") } typename_.append("::"); readNestedName(typename_); skipSpaces(); // check for member operator: e.g. "x::operator" if (isOperatorIdentifier(typename_)) { return false; } } // do some look ahead for the decision (store rollback position const char * rollback = current_; // now check for template declaration: if (tryNextIs('<')) // the use of a template type { // skip template usage: findNextBalanced('<','>'); skipSpaces(); // check if it has parameter: if (tryNextIs('(')) if (!this->tryReadUntilNext(')')) throwFailure("Expect a closed parameter list for this template."); return true; // yes, it's a user defined type ! } // DO SOME LOOK AHEAD TO FIND OUT // a possible declarator that follows: // check existence of a next identifier, this is a sign for a userdefined type... std::string identifier; if (tryReadNextIdentifier(identifier)) { current_ = rollback; return true; } // check for a special case where the declarator starts with a '(' // example: "int (*(*f))(int) const;" if (tryNextIs('(')) // might be the declarator (e.g. "usertype (*f);" or a parameter (e.g. "int userfct()"; { findNextBalanced('(',')'); } // check the characters follow the braces: skipSpaces(); if (tryReadNextIdentifier(identifier)) { // the "const" keyword is allowed for function declarations if (identifier!="const") { // but it's not the 'const' current_ = rollback; return false; // this was not a function-declarator, } } std::string seperators=",;=["; bool ret = seperators.find(*current_) == std::string::npos; current_ = rollback; return ret; } void DeclarationDetailsParser::readNestedName(std::string& nestedname) { std::string nameSpecifier; bool oneMoreLevel; do { oneMoreLevel = false; if (!tryReadNextIdentifier(nameSpecifier)) throwFailure( "Expected an identifier for elaborated type." ); nestedname.append(nameSpecifier); skipSpaces(); // check if identifier is followed by a '::' (additional level if (tryNextIs(':')) { if (!tryNextIs(':')) { --current_; return; // // it's not a "::" - might be the bitfield operator (e.g. "int myvar::sub :0") } nestedname.append("::"); skipSpaces(); oneMoreLevel = true; } } while (oneMoreLevel); backtrackSkippingSpaces(); } void DeclarationDetailsParser::readClassOrEnumSpecifier(ASTNodePtr& specifier, std::string keyword, std::string name) { ASTNodePtr body; int startIndex; if (keyword == "class" || keyword == "struct" || keyword == "union") { // read over possible inheritance information readUntilNextOf("{"); current_++; body = createASTNode( ASTNodeTypes::unparsedDeclarationList, specifier, startIndex = getCurrentIndex(), getCurrentLength() ); specifier->setPropertyNode( ASTNodeProperties::classBodyProperty , body ); } else { specifier->mutateType( ASTNodeTypes::enumSpecifier ); expect('{'); body = createASTNode( ASTNodeTypes::unparsedDeclarationList, specifier, startIndex = getCurrentIndex(), getCurrentLength() ); specifier->setPropertyNode( ASTNodeProperties::enumBodyProperty , body ); } findNextBalanced('{','}'); body->setLength(getCurrentLength() - startIndex - 1 ); // do not count the last '}' } bool DeclarationDetailsParser::tryFindNextBalanced( const char *¤t, const char *end, char opening, char closing ) { int balance = 1; while ( ++current != end ) { char c = *current; if ( c == closing ) { --balance; if ( balance == 0 ) { ++current; return true; } } else if ( c == opening ) ++balance; } return false; } bool DeclarationDetailsParser::skipOverAssignmentInitializer() { const char *start = current_; while ( current_ != end_ ) { char c = *current_; if ( c == ';' || c == ',' ) return current_ != (start+1); else if ( c == '(' ) { if ( !tryFindNextBalanced( current_, end_, '(', ')' ) ) return false; } else if ( c == '[' ) { if ( !tryFindNextBalanced( current_, end_, '[', ']' ) ) return false; } else if ( c == '{' ) { if ( !tryFindNextBalanced( current_, end_, '{', '}' ) ) return false; } else ++current_; } return true; } void DeclarationDetailsParser::parseDeclarators() { Tracker tracker( "DeclarationDetailsParser::parseDeclarators", *this ); int declaratorNumber = 1; while ( current_ != end_ ) { skipSpaces(); int declaratorStartIndex = getCurrentIndex(); // find end of the init-declarator bool declaratorEndReached = false; bool functionDeclarator = false; bool identifierFound = false; do { skipSpaces(); if (tryNextIs('*')) continue; if (tryNextIs('&')) continue; if (tryNextIs('(')) { // check if this is a direct declaration of a function: if (identifierFound) { functionDeclarator = true; findNextBalanced('(',')'); } else { findNextBalanced('(',')'); readUntilNextOf(";,=("); if (tryNextIs('(')) { functionDeclarator = true; findNextBalanced('(',')'); } } declaratorEndReached = true; break; } if (tryNextIs('[')) { findNextBalanced('[',']'); continue; } if (tryNextIs(';') || tryNextIs(',') || tryNextIs('=') || tryNextIs('{')) { declaratorEndReached = true; --current_; break; } std::string nestedName; if (tryNextIs(':')) { if (!tryNextIs(':')) throwFailure("Did not expect a single colon at this stage."); nestedName = "::"; } std::string identifier; if (!tryReadNextIdentifier(identifier)) { throwFailure( boost::format("unexpected character: '%1%'.") % *current_ ); } else { if (identifier=="const") continue; if (identifier=="volatile") continue; identifierFound = true; // read fully qualified name: nestedName.append(identifier); if (tryReadNext("::")) { nestedName.append("::"); readNestedName(nestedName); } // check for operator keyword: if (isOperatorIdentifier(nestedName)) { parseOperator(declaratorStartIndex); return; } // check for bitfield expression if (tryNextIs(':')) { if (!skipOverAssignmentInitializer()) throwFailure("Constant expression is not well formed."); // @todo: store bit field expression } continue; } } while (hasNext() && !declaratorEndReached); if (!declaratorEndReached) { boost::format frmt( "failed to find expected declarator separator " "for declaration %1%: ',;=({'. "); throwFailure( frmt % declaratorNumber ); } if (functionDeclarator) { // read the possible identifiers after function declarator: bool found; do { skipSpaces(); found=false; if (doesKeywordFollow("const") ) { found=true; } if (doesKeywordFollow("volatile") ) { found=true; } } while (found); if (doesKeywordFollow("throw")) { skipSpaces(); expect('('); readUntilNextOf(")"); if (*current_==')') ++current_; } } ASTNodePtr declaratorNode = createASTNode( ASTNodeTypes::unparsedDeclarator, node_, declaratorStartIndex, getCurrentIndex() - declaratorStartIndex ); // the correct length is set when the initializer is added. node_->addChild(declaratorNode); // now go through initializers: createAndAddInitializerNode(declaratorNode); declaratorNumber++; } } void DeclarationDetailsParser::createAndAddInitializerNode( const ASTNodePtr &declaratorNode ) { if ( !hasNext() ) return; Tracker tracker( "DeclarationDetailsParser::createAndAddInitializerNode", *this ); int initializerStartIndex = getCurrentIndex(); int initializerValueStartIndex; int initializerValueEndIndex; int declaratorEndIndex; ASTNodeType initializerType; switch( *current_++ ) { case '=': initializerType = ASTNodeTypes::assignVariableInitializerExpression; skipSpaces(); initializerValueStartIndex = getCurrentIndex(); skipOverAssignmentInitializer(); /// @todo should check return value declaratorEndIndex = getCurrentIndex(); initializerValueEndIndex = getCurrentIndex(); break; case '(': initializerType = ASTNodeTypes::constructorVariableInitializerExpression; initializerValueStartIndex = getCurrentIndex(); findNextBalanced( '(', ')' ); declaratorEndIndex = getCurrentIndex(); initializerValueEndIndex = getCurrentIndex() -1; break; case ';': case ',': case '{': return; default: -- current_; throwFailure( boost::format("unexpected character: '%1%'.") % *current_ ); } declaratorNode->setLength( declaratorEndIndex - declaratorNode->getStartIndex() ); addInitializerNode( declaratorNode, initializerType, initializerStartIndex ); addValueNode( declaratorNode, initializerValueStartIndex, initializerValueEndIndex ); skipSpaces(); if ( !hasNext() ) return; if ( *current_ == ';' || *current_ == ',' ) ++current_; else throwFailure( boost::format("unexpected character: '%1%'.") % *current_ ); } void DeclarationDetailsParser::addValueNode( const ASTNodePtr& declaratorNode, int start, int end) const { ASTNodePtr initializerNode = declaratorNode->getProperty( ASTNodeProperties::variableInitializerProperty ); ASTNodePtr valueNode = createASTNode( ASTNodeTypes::valueExpression, initializerNode, start, end-start); initializerNode->setPropertyNode( ASTNodeProperties::valueProperty, valueNode ); } void DeclarationDetailsParser::addInitializerNode( const ASTNodePtr& declaratorNode, const ASTNodeType initializerType, int initializerStartIndex) const { int initializerLength = getCurrentIndex() - initializerStartIndex; ASTNodePtr initializerNode = createASTNode( initializerType, declaratorNode, initializerStartIndex, initializerLength ); declaratorNode->setPropertyNode( ASTNodeProperties::variableInitializerProperty, initializerNode ); } bool DeclarationDetailsParser::doesKeywordFollow( std::string keyword) { int idx = 0; const char * save = getCurrent(); std::string id; bool retval = tryReadNextIdentifier(id) & id == keyword; if (!retval) current_ = save; return retval; } bool DeclarationDetailsParser::tryReadToken(std::string& token) { std::string collect; switch(*current_++) { case '+': if (*current_== '=' ) { current_++; collect="+="; } else if (*current_== '+' ) { current_++; collect="++"; } else collect="+"; break; case '-': if (*current_== '=' ) { current_++; collect="-="; } else if (*current_== '-' ) { current_++; collect="--"; } else if (*current_== '>' ) { current_++; if (*current_== '*' ) { current_++; collect="->*"; } else collect="->"; } else collect="-"; break; case '*': if (*current_== '=' ) { current_++; collect="*="; } else collect="*"; break; case '/': if (*current_== '=' ) { current_++; collect="/="; } else collect="/"; break; case '^': if (*current_== '=' ) { current_++; collect="^="; } else collect="^"; break; case '&': if (*current_== '=' ) { current_++; collect="&="; } else if (*current_== '&' ) { current_++; collect="&&"; } else collect="&"; break; case '|': if (*current_== '=' ) { current_++; collect="|="; } else if (*current_== '|' ) { current_++; collect="||"; } else collect="|"; break; case '~': collect="~"; break; case '!': if (*current_== '=' ) { current_++; collect="!="; } else collect="!"; break; case '=': if (*current_== '=' ) { current_++; collect="=="; } else collect="="; break; case '<': if (*current_== '=' ) { current_++; collect="<="; } else if (*current_== '<' ) { current_++; if (*current_== '=' ) { current_++; collect="<<="; } else collect="<<"; } else collect="<"; break; case '>': if (*current_== '=' ) { current_++; collect=">="; } else if (*current_== '>' ) { current_++; if (*current_== '=' ) { current_++; collect=">>="; } else collect=">>"; } else collect=">"; break; case ',': collect=","; break; case '(': expect(')'); collect="()"; break; case '[': expect(']'); collect="[]"; break; default: --current_; break; } token = collect; return !token.empty(); } void DeclarationDetailsParser::parseOperator(int declaratorStartIndex) { skipSpaces(); std::string token; if (!tryReadToken(token)) { const char * begin = getCurrent(); if ( doesKeywordFollow("new") ) token += "new"; if ( doesKeywordFollow("delete") ) token += "delete"; if (!token.empty()) { if ( tryReadNext("[]") ) token+="[]"; } } // check if operator overloading has been parsed if (token.empty()) { // this is not the case. // this is 'conversion function declarator': // skip over the type-specifier and ptr-operator elements readUntilNextOf("("); } // now read parameters: (for both operator and conversion function) skipSpaces(); expect('('); findNextBalanced('(',')'); readUntilNextOf("{;=,"); backtrackSkippingSpaces(); ASTNodePtr declaratorNode = createASTNode( ASTNodeTypes::unparsedDeclarator, node_, declaratorStartIndex, getCurrentIndex() - declaratorStartIndex ); node_->addChild(declaratorNode); skipSpaces(); } bool DeclarationDetailsParser::isOperatorIdentifier(std::string name) { unsigned int pos = name.find_last_of(":"); if (pos == std::string::npos) return name=="operator"; return name.substr(pos+1) == "operator"; } } // namespace Refactoring |