📄 yyreg.cpp
字号:
static int yyTok; // the current token/* Returns TRUE if thingy is a constructor or a destructor; otherwise returns FALSE.*/static bool isCtorOrDtor( const QString& thingy ){ // e.g., Alpha<a>::Beta<Bar<b, c> >::~Beta QRegExp xtor( QString( "(?:([A-Z_a-z][0-9A-Z_a-z]*)" // class name "(?:<(?:[^>]|<[^>]*>)*>)*" // template arguments "::)+" // many in a row "~?" // ctor or dtor? "\\1") ); // function has same name as class return xtor.exactMatch( thingy );}/* Skips over any template arguments with balanced angle brackets, and returns the skipped material as a string. Before: QMap < QString , QValueList < QString > > @ m ; After: QMap @ < QString , QValueList < QString > > m ;*/static QString matchTemplateAngles(){ QString t; if ( yyTok == Tok_RightAngle ) { int depth = 0; do { if ( yyTok == Tok_RightAngle ) depth++; else if ( yyTok == Tok_LeftAngle ) depth--; t.prepend( yyLex ); yyTok = getToken(); } while ( depth > 0 && yyTok != Tok_Boi && yyTok != Tok_LeftBrace ); } return t;}/* Similar to matchTemplateAngles(), but for array brackets in parameter data types (as in "int *argv[]").*/static QString matchArrayBrackets(){ QString t; while ( yyTok == Tok_RightBracket ) { t.prepend( yyLex ); yyTok = getToken(); if ( yyTok == Tok_Something ) { t.prepend( yyLex ); yyTok = getToken(); } if ( yyTok != Tok_LeftBracket ) return QString::null; t.prepend( yyLex ); yyTok = getToken(); } return t;}/* Prepends prefix to *type. This operation is in theory trivial, but for the spacing to look good, we have to do something. The original spacing is lost as the input is tokenized.*/static void prependToType( QString *type, const QString& prefix ){ if ( !type->isEmpty() && !prefix.isEmpty() ) { QChar left = prefix[(int) prefix.length() - 1]; QChar right = (*type)[0]; if ( left.isLetter() && (right.isLetter() || right == QChar('*') || right == QChar('&')) ) type->prepend( QChar(' ') ); } type->prepend( prefix );}/* Parses a data type (backwards as usual) and returns a textual representation of it.*/static QString matchDataType(){ QString type; while ( yyTok == Tok_Ampersand || yyTok == Tok_Aster || yyTok == Tok_const ) { prependToType( &type, yyLex ); yyTok = getToken(); } /* This code is really hard to follow... sorry. The loop matches Alpha::Beta::Gamma::...::Omega. */ for ( ;; ) { bool virgin = TRUE; prependToType( &type, matchTemplateAngles() ); if ( yyTok != Tok_Ident ) { /* People may write 'const unsigned short' or 'short unsigned const' or any other permutation. */ while ( yyTok == Tok_const || yyTok == Tok_signed || yyTok == Tok_unsigned || yyTok == Tok_short || yyTok == Tok_long ) { prependToType( &type, yyLex ); yyTok = getToken(); if ( yyTok != Tok_const ) virgin = FALSE; } if ( yyTok == Tok_Tilde ) { prependToType( &type, yyLex ); yyTok = getToken(); } } if ( virgin ) { if ( yyTok == Tok_Ellipsis || yyTok == Tok_Ident || yyTok == Tok_char || yyTok == Tok_int || yyTok == Tok_double ) { prependToType( &type, yyLex ); yyTok = getToken(); } else { return QString::null; } } else if ( yyTok == Tok_int || yyTok == Tok_char || yyTok == Tok_double ) { prependToType( &type, yyLex ); yyTok = getToken(); } while ( yyTok == Tok_const ) { prependToType( &type, yyLex ); yyTok = getToken(); } if ( yyTok == Tok_Gulbrandsen ) { prependToType( &type, yyLex ); yyTok = getToken(); } else { break; } } return type;}/* Parses a function prototype (without the semicolon) and returns an object that stores information about this function.*/static CppFunction matchFunctionPrototype( bool stripParamNames ){ CppFunction func;#if 0 QString documentation;#endif QString returnType; QString scopedName; QStringList params; QString qualifier; bool cnst = FALSE; if ( yyTok == Tok_const ) { cnst = TRUE; yyTok = getToken(); } if ( yyTok != Tok_RightParen ) return func; yyTok = getToken(); if ( yyTok != Tok_LeftParen ) { for ( ;; ) { QString brackets = matchArrayBrackets(); QString name; if ( yyTok == Tok_Ident ) { name = yyLex; yyTok = getToken(); } QString type = matchDataType(); if ( type.isEmpty() ) { if ( name.isEmpty() ) return func; type = name; name = QString::null; } if ( stripParamNames ) name = QString::null; QString param = type + QChar( ' ' ) + name + brackets; params.prepend( param.stripWhiteSpace() ); if ( yyTok != Tok_Comma ) break; yyTok = getToken(); } if ( yyTok != Tok_LeftParen ) return func; } yyTok = getToken(); for ( ;; ) { scopedName.prepend( matchTemplateAngles() ); if ( yyTok != Tok_Ident ) { // the operator keyword should be close int i = 0; while ( i < 4 && yyTok != Tok_operator ) { scopedName.prepend( yyLex ); i++; } if ( yyTok != Tok_operator ) return func; } scopedName.prepend( yyLex ); yyTok = getToken(); if ( yyTok != Tok_Gulbrandsen ) break; scopedName.prepend( yyLex ); yyTok = getToken(); } if ( !isCtorOrDtor(scopedName) ) { returnType = matchDataType(); if ( returnType.isEmpty() ) return func; } /* The documentation feature is unused so far, since we cannot really distinguist between a normal comment between two functions and one that relates to the following function. One good heuristic is to assume that a comment immediately followed by a function with no blank line in between relates to the function, but there's no easy way to find that out with a tokenizer. */#if 0 if ( yyTok == Tok_Comment ) { documentation = yyLex; yyTok = getToken(); } func.setDocumentation( documentation );#endif func.setReturnType( returnType ); func.setScopedName( scopedName ); func.setParameterList( params ); func.setConst( cnst ); return func;}/* Try to set the body. It's not sufficient to call func->setBody(somewhatBody), as the somewhatBody might be too large. Case in point: void foo() { printf( "Hello" ); } int n; void bar() { printf( " world!\n" ); } The parser first finds bar(). Then it finds "void foo() {" and naively expects the body to extend up to "void bar()". This function's job is to count braces and make sure "int n;" is not counted as part of the body. Cases where the closing brace of the body is missing require no special processing.*/static void setBody( CppFunction *func, const QString& somewhatBody ){ QString body = somewhatBody; int braceDepth = 0; int i = 0; while ( i < (int) body.length() ) { if ( body[i] == QChar('{') ) { braceDepth++; } else if ( body[i] == QChar('}') ) { braceDepth--; if ( braceDepth == 0 ) { body.truncate( i + 1 ); break; } } i++; } func->setBody( body );}/* Parses a whole C++ file, looking for function definitions. Case in point: void foo() { printf( "Hello" ); void bar() { printf( " world!\n" ); } The parser looks for left braces and tries to parse a function prototype backwards. First it finds "void bar() {". Then it works up and finds "void foo() {".*/static void matchTranslationUnit( QValueList<CppFunction> *flist ){ int endBody = -1; int startBody; for ( ;; ) { if ( endBody == -1 ) endBody = yyPos; while ( yyTok != Tok_Boi && yyTok != Tok_LeftBrace ) yyTok = getToken(); if ( yyTok == Tok_Boi ) break; // found a left brace yyTok = getToken(); startBody = yyPos; CppFunction func = matchFunctionPrototype( FALSE ); if ( !func.scopedName().isEmpty() ) { QString body = yyIn->mid( startBody, endBody - startBody ); setBody( &func, body ); body = func.body(); // setBody() can change the body /* Compute important line numbers. */ int functionStartLineNo = 1 + QConstString( yyIn->unicode(), yyPos ) .string().contains( QChar('\n') ); int startLineNo = functionStartLineNo + QConstString( yyIn->unicode() + yyPos, startBody - yyPos ) .string().contains( QChar('\n') ); int endLineNo = startLineNo + body.contains( QChar('\n') ); func.setLineNums( functionStartLineNo, startLineNo, endLineNo ); flist->prepend( func ); endBody = -1; } }}/* Extracts C++ function from source code and put them in a list.*/void extractCppFunctions( const QString& code, QValueList<CppFunction> *flist ){ startTokenizer( code ); yyTok = getToken(); matchTranslationUnit( flist ); stopTokenizer();}/* Returns the prototype with the parameter names removed.*/QString canonicalCppProto( const QString& proto ){ startTokenizer( proto ); yyTok = getToken(); CppFunction func = matchFunctionPrototype( TRUE ); stopTokenizer(); return func.prototype();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -