|
|
|
/* This file is part of KDevelop
|
|
|
|
Copyright (C) 2002,2003 Roberto Raggi <roberto@tdevelop.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef PARSER_H
|
|
|
|
#define PARSER_H
|
|
|
|
|
|
|
|
#include "ast.h"
|
|
|
|
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqvaluelist.h>
|
|
|
|
#include <tqvaluestack.h>
|
|
|
|
#include <set>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
struct ParserPrivateData;
|
|
|
|
|
|
|
|
class Driver;
|
|
|
|
class Lexer;
|
|
|
|
class Token;
|
|
|
|
struct Error;
|
|
|
|
|
|
|
|
|
|
|
|
class CommentFormatter {
|
|
|
|
static inline bool isWhite( TQChar c ) {
|
|
|
|
return c.isSpace();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rStrip( TQString str, TQString& from ) {
|
|
|
|
if( str.isEmpty() ) return;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
int ip = from.length();
|
|
|
|
int s = from.length();
|
|
|
|
|
|
|
|
for( int a = s-1; a >= 0; a-- ) {
|
|
|
|
if( isWhite( from[a] ) ) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
if( from[a] == str[i] ) {
|
|
|
|
i++;
|
|
|
|
ip = a;
|
|
|
|
if( i == (int)str.length() ) break;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ip != (int)from.length() ) from = from.left( ip );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void strip( TQString str, TQString& from ) {
|
|
|
|
if( str.isEmpty() ) return;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
int ip = 0;
|
|
|
|
int s = from.length();
|
|
|
|
|
|
|
|
for( int a = 0; a < s; a++ ) {
|
|
|
|
if( isWhite( from[a] ) ) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
if( from[a] == str[i] ) {
|
|
|
|
i++;
|
|
|
|
ip = a+1;
|
|
|
|
if( i == (int)str.length() ) break;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ip ) from = from.mid( ip );
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
static TQString formatComment( TQString comment ) {
|
|
|
|
TQString ret;
|
|
|
|
int i = 0;
|
|
|
|
int s = comment.length();
|
|
|
|
while( i < s && comment[i] == '/' ) {
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i > 1 ) {
|
|
|
|
ret = comment.mid( i );
|
|
|
|
} else {
|
|
|
|
///remove the star in each line
|
|
|
|
TQStringList lines = TQStringList::split( "\n", comment );
|
|
|
|
|
|
|
|
if( lines.isEmpty() ) return ret;
|
|
|
|
|
|
|
|
strip( "/**", lines.front() );
|
|
|
|
rStrip( "/**", lines.back() );
|
|
|
|
|
|
|
|
TQStringList::iterator it = lines.begin();
|
|
|
|
++it;
|
|
|
|
TQStringList::iterator eit = lines.end();
|
|
|
|
|
|
|
|
if( it != lines.end() ) {
|
|
|
|
--eit;
|
|
|
|
|
|
|
|
for( ; it != eit; ++it ) {
|
|
|
|
strip( "*", *it );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( lines.front().stripWhiteSpace().isEmpty() )
|
|
|
|
lines.pop_front();
|
|
|
|
|
|
|
|
if( lines.back().stripWhiteSpace().isEmpty() )
|
|
|
|
lines.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = lines.join( "\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Comment {
|
|
|
|
TQString m_text;
|
|
|
|
int m_line;
|
|
|
|
bool m_formatted;
|
|
|
|
|
|
|
|
|
|
|
|
void format() {
|
|
|
|
if( m_formatted ) return;
|
|
|
|
m_formatted = true;
|
|
|
|
m_text = CommentFormatter::formatComment( m_text );
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
Comment( TQString text = "", int line = -1 ) : m_text( text ), m_line( line ), m_formatted(false) {
|
|
|
|
}
|
|
|
|
|
|
|
|
Comment( int line ) : m_line( line ) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator += ( Comment rhs ) {
|
|
|
|
format();
|
|
|
|
rhs.format();
|
|
|
|
m_text += " " + rhs.m_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator bool() const {
|
|
|
|
return !m_text.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
operator TQString() {
|
|
|
|
format();
|
|
|
|
return m_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int line() const {
|
|
|
|
return m_line;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator < ( Comment& rhs ) const {
|
|
|
|
return m_line < rhs.m_line;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isSame ( const Comment& rhs ) {
|
|
|
|
if( rhs.m_formatted ) format();
|
|
|
|
return m_text == rhs.m_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cmp {
|
|
|
|
bool operator () ( const Comment& c1, const Comment& c2 ) const {
|
|
|
|
return c1.line() < c2.line();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class CommentStore {
|
|
|
|
private:
|
|
|
|
typedef std::set< Comment, Comment::cmp > CommentSet;
|
|
|
|
CommentSet m_comments;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
///Returns the comment nearest to "end"(inclusive), and returns & removes it
|
|
|
|
Comment getCommentInRange( int end, int start = 0 ) {
|
|
|
|
CommentSet::iterator it = m_comments.lower_bound( end );
|
|
|
|
|
|
|
|
|
|
|
|
while( it != m_comments.begin() && (*it).line() > end ) {
|
|
|
|
--it;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( it != m_comments.end() && (*it).line() >= start && (*it).line() <= end ) {
|
|
|
|
Comment ret = *it;
|
|
|
|
m_comments.erase( it );
|
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
return Comment();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///Returns and removes the comment in the line
|
|
|
|
Comment getComment( int line ) {
|
|
|
|
CommentSet::iterator it = m_comments.find( line );
|
|
|
|
if( it != m_comments.end() ) {
|
|
|
|
Comment ret = *it;
|
|
|
|
m_comments.erase( it );
|
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
return Comment();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void addComment( Comment comment ) {
|
|
|
|
|
|
|
|
CommentSet::iterator it = m_comments.find( comment );
|
|
|
|
if( it != m_comments.end() ) {
|
|
|
|
if( comment.isSame( *it ) ) return;
|
|
|
|
Comment c = *it;
|
|
|
|
c += comment;
|
|
|
|
comment = c;
|
|
|
|
m_comments.erase( it );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_comments.insert( comment );
|
|
|
|
}
|
|
|
|
|
|
|
|
///Does not delete the comment
|
|
|
|
Comment latestComment() {
|
|
|
|
CommentSet::iterator it = m_comments.end();
|
|
|
|
if( it == m_comments.begin() ) return Comment();
|
|
|
|
--it;
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear() {
|
|
|
|
m_comments.clear();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Parser
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Parser( Driver* driver, Lexer* lexer );
|
|
|
|
virtual ~Parser();
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual bool reportError( const Error& err );
|
|
|
|
/** @todo remove*/ virtual bool reportError( const TQString& msg );
|
|
|
|
/** @todo remove*/ virtual void syntaxError();
|
|
|
|
|
|
|
|
public /*rules*/ :
|
|
|
|
|
|
|
|
bool parseTranslationUnit( TranslationUnitAST::Node& node );
|
|
|
|
|
|
|
|
bool parseDeclaration( DeclarationAST::Node& node );
|
|
|
|
bool parseBlockDeclaration( DeclarationAST::Node& node );
|
|
|
|
bool parseLinkageSpecification( DeclarationAST::Node& node );
|
|
|
|
bool parseLinkageBody( LinkageBodyAST::Node& node );
|
|
|
|
bool parseNamespace( DeclarationAST::Node& node );
|
|
|
|
bool parseNamespaceAliasDefinition( DeclarationAST::Node& node );
|
|
|
|
bool parseUsing( DeclarationAST::Node& node );
|
|
|
|
bool parseUsingDirective( DeclarationAST::Node& node );
|
|
|
|
bool parseTypedef( DeclarationAST::Node& node );
|
|
|
|
bool parseAsmDefinition( DeclarationAST::Node& node );
|
|
|
|
bool parseTemplateDeclaration( DeclarationAST::Node& node );
|
|
|
|
bool parseDeclarationInternal( DeclarationAST::Node& node );
|
|
|
|
|
|
|
|
bool parseUnqualifiedName( ClassOrNamespaceNameAST::Node& node );
|
|
|
|
bool parseStringLiteral( AST::Node& node );
|
|
|
|
bool parseName( NameAST::Node& node );
|
|
|
|
bool parseOperatorFunctionId( AST::Node& node );
|
|
|
|
bool parseTemplateArgumentList( TemplateArgumentListAST::Node& node, bool reportError=true );
|
|
|
|
bool parseOperator( AST::Node& node );
|
|
|
|
bool parseCvQualify( GroupAST::Node& node );
|
|
|
|
bool parseSimpleTypeSpecifier( TypeSpecifierAST::Node& node );
|
|
|
|
bool parsePtrOperator( AST::Node& node );
|
|
|
|
bool parseTemplateArgument( AST::Node& node );
|
|
|
|
bool parseTypeSpecifier( TypeSpecifierAST::Node& node );
|
|
|
|
bool parseTypeSpecifierOrClassSpec( TypeSpecifierAST::Node& node );
|
|
|
|
bool parseDeclarator( DeclaratorAST::Node& node );
|
|
|
|
bool parseTemplateParameterList( TemplateParameterListAST::Node& node );
|
|
|
|
bool parseTemplateParameter( TemplateParameterAST::Node& node );
|
|
|
|
bool parseStorageClassSpecifier( GroupAST::Node& node );
|
|
|
|
bool parseFunctionSpecifier( GroupAST::Node& node );
|
|
|
|
bool parseInitDeclaratorList( InitDeclaratorListAST::Node& node );
|
|
|
|
bool parseInitDeclarator( InitDeclaratorAST::Node& node );
|
|
|
|
bool parseParameterDeclarationClause( ParameterDeclarationClauseAST::Node& node );
|
|
|
|
bool parseCtorInitializer( AST::Node& node );
|
|
|
|
bool parsePtrToMember( AST::Node& node );
|
|
|
|
bool parseEnumSpecifier( TypeSpecifierAST::Node& node );
|
|
|
|
bool parseClassSpecifier( TypeSpecifierAST::Node& node );
|
|
|
|
bool parseWinDeclSpec( GroupAST::Node& node );
|
|
|
|
bool parseElaboratedTypeSpecifier( TypeSpecifierAST::Node& node );
|
|
|
|
bool parseDeclaratorId( NameAST::Node& node );
|
|
|
|
bool parseExceptionSpecification( GroupAST::Node& node );
|
|
|
|
bool parseEnumerator( EnumeratorAST::Node& node );
|
|
|
|
bool parseTypeParameter( TypeParameterAST::Node& node );
|
|
|
|
bool parseParameterDeclaration( ParameterDeclarationAST::Node& node );
|
|
|
|
bool parseTypeId( AST::Node& node );
|
|
|
|
bool parseAbstractDeclarator( DeclaratorAST::Node& node );
|
|
|
|
bool parseParameterDeclarationList( ParameterDeclarationListAST::Node& node );
|
|
|
|
bool parseMemberSpecification( DeclarationAST::Node& node );
|
|
|
|
bool parseAccessSpecifier( AST::Node& node );
|
|
|
|
bool parseTypeIdList( GroupAST::Node& node );
|
|
|
|
bool parseMemInitializerList( AST::Node& node );
|
|
|
|
bool parseMemInitializer( AST::Node& node );
|
|
|
|
bool parseInitializer( AST::Node& node );
|
|
|
|
bool parseBaseClause( BaseClauseAST::Node& node );
|
|
|
|
bool parseBaseSpecifier( BaseSpecifierAST::Node& node );
|
|
|
|
bool parseInitializerClause( AST::Node& node );
|
|
|
|
bool parseMemInitializerId( NameAST::Node& node );
|
|
|
|
bool parseFunctionBody( StatementListAST::Node& node );
|
|
|
|
|
|
|
|
// expression
|
|
|
|
bool skipExpression( AST::Node& node );
|
|
|
|
bool skipCommaExpression( AST::Node& node );
|
|
|
|
bool skipExpressionStatement( StatementAST::Node& node );
|
|
|
|
|
|
|
|
bool parseExpression( AST::Node& node );
|
|
|
|
bool parsePrimaryExpression( AST::Node& node );
|
|
|
|
bool parsePostfixExpression( AST::Node& node );
|
|
|
|
bool parseUnaryExpression( AST::Node& node );
|
|
|
|
bool parseNewExpression( AST::Node& node );
|
|
|
|
bool parseNewTypeId( AST::Node& node );
|
|
|
|
bool parseNewDeclarator( AST::Node& node );
|
|
|
|
bool parseNewInitializer( AST::Node& node );
|
|
|
|
bool parseDeleteExpression( AST::Node& node );
|
|
|
|
bool parseCastExpression( AST::Node& node );
|
|
|
|
bool parsePmExpression( AST::Node& node );
|
|
|
|
bool parseMultiplicativeExpression( AST::Node& node );
|
|
|
|
bool parseAdditiveExpression( AST::Node& node );
|
|
|
|
bool parseShiftExpression( AST::Node& node );
|
|
|
|
bool parseRelationalExpression( AST::Node& node, bool templArgs=false );
|
|
|
|
bool parseEqualityExpression( AST::Node& node, bool templArgs=false );
|
|
|
|
bool parseAndExpression( AST::Node& node, bool templArgs=false );
|
|
|
|
bool parseExclusiveOrExpression( AST::Node& node, bool templArgs=false );
|
|
|
|
bool parseInclusiveOrExpression( AST::Node& node, bool templArgs=false );
|
|
|
|
bool parseLogicalAndExpression( AST::Node& node, bool templArgs=false );
|
|
|
|
bool parseLogicalOrExpression( AST::Node& node, bool templArgs=false );
|
|
|
|
bool parseConditionalExpression( AST::Node& node );
|
|
|
|
bool parseAssignmentExpression( AST::Node& node );
|
|
|
|
bool parseConstantExpression( AST::Node& node );
|
|
|
|
bool parseCommaExpression( AST::Node& node );
|
|
|
|
bool parseThrowExpression( AST::Node& node );
|
|
|
|
|
|
|
|
// statement
|
|
|
|
bool parseCondition( ConditionAST::Node& node );
|
|
|
|
bool parseStatement( StatementAST::Node& node );
|
|
|
|
bool parseWhileStatement( StatementAST::Node& node );
|
|
|
|
bool parseDoStatement( StatementAST::Node& node );
|
|
|
|
bool parseForStatement( StatementAST::Node& node );
|
|
|
|
bool parseForEachStatement( StatementAST::Node& node ); // qt4 [erbsland]
|
|
|
|
bool parseCompoundStatement( StatementAST::Node& node );
|
|
|
|
bool parseForInitStatement( StatementAST::Node& node );
|
|
|
|
bool parseIfStatement( StatementAST::Node& node );
|
|
|
|
bool parseSwitchStatement( StatementAST::Node& node );
|
|
|
|
bool parseLabeledStatement( StatementAST::Node& node );
|
|
|
|
bool parseDeclarationStatement( StatementAST::Node& node );
|
|
|
|
bool parseTryBlockStatement( StatementAST::Node& node );
|
|
|
|
|
|
|
|
// objective c
|
|
|
|
bool parseObjcDef( DeclarationAST::Node& node );
|
|
|
|
bool parseObjcClassDef( DeclarationAST::Node& node );
|
|
|
|
bool parseObjcClassDecl( DeclarationAST::Node& node );
|
|
|
|
bool parseObjcProtocolDecl( DeclarationAST::Node& node );
|
|
|
|
bool parseObjcAliasDecl( DeclarationAST::Node& node );
|
|
|
|
bool parseObjcProtocolDef( DeclarationAST::Node& node );
|
|
|
|
bool parseObjcMethodDef( DeclarationAST::Node& node );
|
|
|
|
|
|
|
|
bool parseIvarDeclList( AST::Node& node );
|
|
|
|
bool parseIvarDecls( AST::Node& node );
|
|
|
|
bool parseIvarDecl( AST::Node& node );
|
|
|
|
bool parseIvars( AST::Node& node );
|
|
|
|
bool parseIvarDeclarator( AST::Node& node );
|
|
|
|
bool parseMethodDecl( AST::Node& node );
|
|
|
|
bool parseUnarySelector( AST::Node& node );
|
|
|
|
bool parseKeywordSelector( AST::Node& node );
|
|
|
|
bool parseSelector( AST::Node& node );
|
|
|
|
bool parseKeywordDecl( AST::Node& node );
|
|
|
|
bool parseReceiver( AST::Node& node );
|
|
|
|
bool parseObjcMessageExpr( AST::Node& node );
|
|
|
|
bool parseMessageArgs( AST::Node& node );
|
|
|
|
bool parseKeywordExpr( AST::Node& node );
|
|
|
|
bool parseKeywordArgList( AST::Node& node );
|
|
|
|
bool parseKeywordArg( AST::Node& node );
|
|
|
|
bool parseReservedWord( AST::Node& node );
|
|
|
|
bool parseMyParms( AST::Node& node );
|
|
|
|
bool parseMyParm( AST::Node& node );
|
|
|
|
bool parseOptParmList( AST::Node& node );
|
|
|
|
bool parseObjcSelectorExpr( AST::Node& node );
|
|
|
|
bool parseSelectorArg( AST::Node& node );
|
|
|
|
bool parseKeywordNameList( AST::Node& node );
|
|
|
|
bool parseKeywordName( AST::Node& node );
|
|
|
|
bool parseObjcEncodeExpr( AST::Node& node );
|
|
|
|
bool parseObjcString( AST::Node& node );
|
|
|
|
bool parseProtocolRefs( AST::Node& node );
|
|
|
|
bool parseIdentifierList( GroupAST::Node& node );
|
|
|
|
bool parseIdentifierColon( AST::Node& node );
|
|
|
|
bool parseObjcProtocolExpr( AST::Node& node );
|
|
|
|
bool parseObjcOpenBracketExpr( AST::Node& node );
|
|
|
|
bool parseObjcCloseBracket( AST::Node& node );
|
|
|
|
|
|
|
|
void nextToken( bool skipComments = true );
|
|
|
|
|
|
|
|
///parses all comments until the end of the line
|
|
|
|
Comment comment();
|
|
|
|
void preparseLineComments( int line );
|
|
|
|
void processComment( int offset = 0 );
|
|
|
|
void clearComment( );
|
|
|
|
|
|
|
|
bool skipUntil( int token );
|
|
|
|
bool skipUntilDeclaration();
|
|
|
|
bool skipUntilStatement();
|
|
|
|
bool skip( int l, int r );
|
|
|
|
TQString toString( int start, int end, const TQString& sep=" " ) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
int currentLine();
|
|
|
|
CommentStore m_commentStore;
|
|
|
|
|
|
|
|
template<class Type>
|
|
|
|
void eventuallyTakeComment( int startLn, int line, Type& ast );
|
|
|
|
template<class Type>
|
|
|
|
void eventuallyTakeComment( Type& ast );
|
|
|
|
|
|
|
|
ParserPrivateData* d;
|
|
|
|
Driver* m_driver;
|
|
|
|
Lexer* lex;
|
|
|
|
Comment m_currentComment;
|
|
|
|
int m_problems;
|
|
|
|
int m_maxProblems;
|
|
|
|
bool objcp;
|
|
|
|
|
|
|
|
private:
|
|
|
|
Parser( const Parser& source );
|
|
|
|
void operator = ( const Parser& source );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|