Cppcheck
token.cpp
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include "token.h"
00020 #include "errorlogger.h"
00021 #include "check.h"
00022 #include <cassert>
00023 #include <cstdlib>
00024 #include <cstring>
00025 #include <string>
00026 #include <iostream>
00027 #include <cctype>
00028 #include <sstream>
00029 #include <map>
00030 
00031 Token::Token(Token **t) :
00032     tokensBack(t),
00033     _next(0),
00034     _previous(0),
00035     _link(0),
00036     _scope(0),
00037     _function(0), // Initialize whole union
00038     _str(""),
00039     _varId(0),
00040     _fileIndex(0),
00041     _linenr(0),
00042     _progressValue(0),
00043     _type(eNone),
00044     _isUnsigned(false),
00045     _isSigned(false),
00046     _isPointerCompare(false),
00047     _isLong(false),
00048     _isUnused(false),
00049     _isStandardType(false),
00050     _isExpandedMacro(false),
00051     _astOperand1(NULL),
00052     _astOperand2(NULL),
00053     _astParent(NULL)
00054 {
00055 }
00056 
00057 Token::~Token()
00058 {
00059 
00060 }
00061 
00062 void Token::update_property_info()
00063 {
00064     if (!_str.empty()) {
00065         if (_str == "true" || _str == "false")
00066             _type = eBoolean;
00067         else if (_str[0] == '_' || std::isalpha(_str[0])) { // Name
00068             if (_varId)
00069                 _type = eVariable;
00070             else if (_type != eVariable && _type != eFunction && _type != eType)
00071                 _type = eName;
00072         } else if (std::isdigit(_str[0]) || (_str.length() > 1 && _str[0] == '-' && std::isdigit(_str[1])))
00073             _type = eNumber;
00074         else if (_str.length() > 1 && _str[0] == '"' && _str[_str.length()-1] == '"')
00075             _type = eString;
00076         else if (_str.length() > 1 && _str[0] == '\'' && _str[_str.length()-1] == '\'')
00077             _type = eChar;
00078         else if (_str == "="   ||
00079                  _str == "+="  ||
00080                  _str == "-="  ||
00081                  _str == "*="  ||
00082                  _str == "/="  ||
00083                  _str == "%="  ||
00084                  _str == "&="  ||
00085                  _str == "^="  ||
00086                  _str == "|="  ||
00087                  _str == "<<=" ||
00088                  _str == ">>=")
00089             _type = eAssignmentOp;
00090         else if (_str.size() == 1 && _str.find_first_of(",[]()?:") != std::string::npos)
00091             _type = eExtendedOp;
00092         else if (_str=="<<" || _str==">>" || (_str.size()==1 && _str.find_first_of("+-*/%") != std::string::npos))
00093             _type = eArithmeticalOp;
00094         else if (_str.size() == 1 && _str.find_first_of("&|^~") != std::string::npos)
00095             _type = eBitOp;
00096         else if (_str == "&&" ||
00097                  _str == "||" ||
00098                  _str == "!")
00099             _type = eLogicalOp;
00100         else if ((_str == "==" ||
00101                   _str == "!=" ||
00102                   _str == "<"  ||
00103                   _str == "<=" ||
00104                   _str == ">"  ||
00105                   _str == ">=") && !_link)
00106             _type = eComparisonOp;
00107         else if (_str == "++" ||
00108                  _str == "--")
00109             _type = eIncDecOp;
00110         else if (_str.size() == 1 && (_str.find_first_of("{}") != std::string::npos || (_link && _str.find_first_of("<>") != std::string::npos)))
00111             _type = eBracket;
00112         else
00113             _type = eOther;
00114     } else {
00115         _type = eNone;
00116     }
00117 
00118     update_property_isStandardType();
00119 }
00120 
00121 void Token::update_property_isStandardType()
00122 {
00123     _isStandardType = false;
00124 
00125     if (_str.size() < 3)
00126         return;
00127 
00128     static const char * const stdtype[] = {"int", "char", "bool", "long", "short", "float", "double", "wchar_t", "size_t", 0};
00129     for (int i = 0; stdtype[i]; i++) {
00130         if (_str == stdtype[i]) {
00131             _isStandardType = true;
00132             _type = eType;
00133             break;
00134         }
00135     }
00136 }
00137 
00138 
00139 bool Token::isUpperCaseName() const
00140 {
00141     if (!isName())
00142         return false;
00143     for (unsigned int i = 0; i < _str.length(); ++i) {
00144         if (std::islower(_str[i]))
00145             return false;
00146     }
00147     return true;
00148 }
00149 
00150 void Token::str(const std::string &s)
00151 {
00152     _str = s;
00153     _varId = 0;
00154 
00155     update_property_info();
00156 }
00157 
00158 void Token::concatStr(std::string const& b)
00159 {
00160     _str.erase(_str.length() - 1);
00161     _str.append(b.begin() + 1, b.end());
00162 
00163     update_property_info();
00164 }
00165 
00166 std::string Token::strValue() const
00167 {
00168     assert(_type == eString);
00169     return _str.substr(1, _str.length() - 2);
00170 }
00171 
00172 void Token::deleteNext(unsigned long index)
00173 {
00174     while (_next && index--) {
00175         Token *n = _next;
00176         _next = n->next();
00177         delete n;
00178     }
00179 
00180     if (_next)
00181         _next->previous(this);
00182     else if (tokensBack)
00183         *tokensBack = this;
00184 }
00185 
00186 void Token::deleteThis()
00187 {
00188     if (_next) { // Copy next to this and delete next
00189         _str = _next->_str;
00190         _type = _next->_type;
00191         _isUnsigned = _next->_isUnsigned;
00192         _isSigned = _next->_isSigned;
00193         _isPointerCompare = _next->_isPointerCompare;
00194         _isLong = _next->_isLong;
00195         _isUnused = _next->_isUnused;
00196         _isStandardType = _next->_isStandardType;
00197         _isExpandedMacro = _next->_isExpandedMacro;
00198         _varId = _next->_varId;
00199         _fileIndex = _next->_fileIndex;
00200         _linenr = _next->_linenr;
00201         _link = _next->_link;
00202         _scope = _next->_scope;
00203         _function = _next->_function;
00204         _variable = _next->_variable;
00205         if (_link)
00206             _link->link(this);
00207 
00208         deleteNext();
00209     } else if (_previous && _previous->_previous) { // Copy previous to this and delete previous
00210         _str = _previous->_str;
00211         _type = _previous->_type;
00212         _isUnsigned = _previous->_isUnsigned;
00213         _isSigned = _previous->_isSigned;
00214         _isPointerCompare = _previous->_isPointerCompare;
00215         _isLong = _previous->_isLong;
00216         _isUnused = _previous->_isUnused;
00217         _isStandardType = _previous->_isStandardType;
00218         _isExpandedMacro = _previous->_isExpandedMacro;
00219         _varId = _previous->_varId;
00220         _fileIndex = _previous->_fileIndex;
00221         _linenr = _previous->_linenr;
00222         _link = _previous->_link;
00223         _scope = _previous->_scope;
00224         _function = _previous->_function;
00225         _variable = _previous->_variable;
00226         if (_link)
00227             _link->link(this);
00228 
00229         Token* toDelete = _previous;
00230         _previous = _previous->_previous;
00231         _previous->_next = this;
00232 
00233         delete toDelete;
00234     } else {
00235         // We are the last token in the list, we can't delete
00236         // ourselves, so just make us empty
00237         str("");
00238     }
00239 }
00240 
00241 void Token::replace(Token *replaceThis, Token *start, Token *end)
00242 {
00243     // Fix the whole in the old location of start and end
00244     if (start->previous())
00245         start->previous()->next(end->next());
00246 
00247     if (end->next())
00248         end->next()->previous(start->previous());
00249 
00250     // Move start and end to their new location
00251     if (replaceThis->previous())
00252         replaceThis->previous()->next(start);
00253 
00254     if (replaceThis->next())
00255         replaceThis->next()->previous(end);
00256 
00257     start->previous(replaceThis->previous());
00258     end->next(replaceThis->next());
00259 
00260     if (end->tokensBack && *(end->tokensBack) == end) {
00261         while (end->next())
00262             end = end->next();
00263         *(end->tokensBack) = end;
00264     }
00265 
00266     // Update _progressValue, fileIndex and linenr
00267     for (Token *tok = start; tok != end->next(); tok = tok->next())
00268         tok->_progressValue = replaceThis->_progressValue;
00269 
00270     // Delete old token, which is replaced
00271     delete replaceThis;
00272 }
00273 
00274 const Token *Token::tokAt(int index) const
00275 {
00276     const Token *tok = this;
00277     int num = std::abs(index);
00278     while (num > 0 && tok) {
00279         if (index > 0)
00280             tok = tok->next();
00281         else
00282             tok = tok->previous();
00283         --num;
00284     }
00285     return tok;
00286 }
00287 
00288 const Token *Token::linkAt(int index) const
00289 {
00290     const Token *tok = this->tokAt(index);
00291     if (!tok) {
00292         throw InternalError(this, "Internal error. Token::linkAt called with index outside the tokens range.");
00293     }
00294     return tok->link();
00295 }
00296 
00297 const std::string &Token::strAt(int index) const
00298 {
00299     static const std::string empty_str;
00300 
00301     const Token *tok = this->tokAt(index);
00302     return tok ? tok->_str : empty_str;
00303 }
00304 
00305 static int multiComparePercent(const Token *tok, const char * * haystack_p,
00306                                const char * needle,
00307                                bool emptyStringFound)
00308 {
00309     const char *haystack = *haystack_p;
00310 
00311     if (haystack[0] == '%' && haystack[1] != '|' && haystack[1] != '\0' && haystack[1] != ' ') {
00312         if (haystack[1] == 'o' && // "%op%"
00313             haystack[2] == 'p' &&
00314             haystack[3] == '%') {
00315             if (tok->isOp())
00316                 return 1;
00317             *haystack_p = haystack = haystack + 4;
00318         } else if (haystack[1] == 'c' && // "%cop%"
00319                    haystack[2] == 'o' &&
00320                    haystack[3] == 'p' &&
00321                    haystack[4] == '%') {
00322             if (tok->isConstOp())
00323                 return 1;
00324             *haystack_p = haystack = haystack + 5;
00325         } else if (haystack[1] == 'o' && // "%or%"
00326                    haystack[2] == 'r' &&
00327                    haystack[3] == '%') {
00328             if (*needle == '|' && needle[1] != '|' && needle[1] != '=')
00329                 return 1;
00330             *haystack_p = haystack = haystack + 4;
00331         } else if (haystack[1] == 'o' && // "%oror%"
00332                    haystack[2] == 'r' &&
00333                    haystack[3] == 'o' &&
00334                    haystack[4] == 'r' &&
00335                    haystack[5] == '%') {
00336             if (needle[0] == '|' && needle[1] == '|')
00337                 return 1;
00338             *haystack_p = haystack = haystack + 6;
00339         }
00340 
00341         if (*haystack == '|')
00342             *haystack_p = haystack = haystack + 1;
00343         else if (*haystack == ' ' || *haystack == '\0')
00344             return emptyStringFound ? 0 : -1;
00345         else
00346             return -1;
00347     }
00348 
00349     return 0xFFFF;
00350 }
00351 
00352 int Token::multiCompare(const Token *tok, const char *haystack, const char *needle)
00353 {
00354     if (haystack[0] == '%' && haystack[1] == 'o') {
00355         if (haystack[2] == 'p' && // "%op%|"
00356             haystack[3] == '%' &&
00357             haystack[4] == '|') {
00358             haystack = haystack + 5;
00359             if (tok->isOp())
00360                 return 1;
00361         } else if (haystack[2] == 'r' && // "%or%|"
00362                    haystack[3] == '%' &&
00363                    haystack[4] == '|') {
00364             haystack = haystack + 5;
00365             if (*needle == '|' && needle[1] != '|' && needle[1] != '=')
00366                 return 1;
00367         } else if (haystack[2] == 'r' && // "%oror%|"
00368                    haystack[3] == 'o' &&
00369                    haystack[4] == 'r' &&
00370                    haystack[5] == '%' &&
00371                    haystack[6] == '|') {
00372             haystack = haystack + 7;
00373             if (needle[0] == '|' && needle[1] == '|')
00374                 return 1;
00375         }
00376     } else if (haystack[0] == '%' && haystack[1] == 'c' && haystack[2] == 'o' && // "%cop%|"
00377                haystack[3] == 'p' && haystack[4] == '%' &&
00378                haystack[5] == '|') {
00379         haystack = haystack + 6;
00380         if (tok->isConstOp())
00381             return 1;
00382     }
00383 
00384     bool emptyStringFound = false;
00385     const char *needlePointer = needle;
00386     for (;;) {
00387         if (*needlePointer == *haystack) {
00388             if (*needlePointer == '\0')
00389                 return 1;
00390             ++needlePointer;
00391             ++haystack;
00392         } else if (*haystack == '|') {
00393             if (*needlePointer == 0) {
00394                 // If needle is at the end, we have a match.
00395                 return 1;
00396             } else if (needlePointer == needle) {
00397                 // If needlePointer was not increased at all, we had a empty
00398                 // string in the haystack
00399                 emptyStringFound = true;
00400             }
00401 
00402             needlePointer = needle;
00403             ++haystack;
00404 
00405             int ret = multiComparePercent(tok, &haystack, needle, emptyStringFound);
00406             if (ret < 2)
00407                 return ret;
00408         } else if (*haystack == ' ' || *haystack == '\0') {
00409             if (needlePointer == needle)
00410                 return 0;
00411             break;
00412         }
00413         // If haystack and needle don't share the same character,
00414         // find next '|' character.
00415         else {
00416             needlePointer = needle;
00417 
00418             do {
00419                 ++haystack;
00420             } while (*haystack != ' ' && *haystack != '|' && *haystack);
00421 
00422             if (*haystack == ' ' || *haystack == '\0') {
00423                 return emptyStringFound ? 0 : -1;
00424             }
00425 
00426             ++haystack;
00427 
00428             int ret = multiComparePercent(tok, &haystack, needle, emptyStringFound);
00429             if (ret < 2)
00430                 return ret;
00431         }
00432     }
00433 
00434     if (*needlePointer == '\0')
00435         return 1;
00436 
00437     // If empty string was found earlier from the haystack
00438     if (emptyStringFound)
00439         return 0;
00440 
00441     return -1;
00442 }
00443 
00444 bool Token::simpleMatch(const Token *tok, const char pattern[])
00445 {
00446     const char *current, *next;
00447 
00448     current = pattern;
00449     next = std::strchr(pattern, ' ');
00450     if (!next)
00451         next = pattern + std::strlen(pattern);
00452 
00453     while (*current) {
00454         std::size_t length = static_cast<std::size_t>(next - current);
00455 
00456         if (!tok || length != tok->_str.length() || std::strncmp(current, tok->_str.c_str(), length))
00457             return false;
00458 
00459         current = next;
00460         if (*next) {
00461             next = std::strchr(++current, ' ');
00462             if (!next)
00463                 next = current + std::strlen(current);
00464         }
00465         tok = tok->next();
00466     }
00467 
00468     return true;
00469 }
00470 
00471 bool Token::firstWordEquals(const char *str, const char *word)
00472 {
00473     for (;;) {
00474         if (*str != *word) {
00475             return (*str == ' ' && *word == 0);
00476         } else if (*str == 0)
00477             break;
00478 
00479         ++str;
00480         ++word;
00481     }
00482 
00483     return true;
00484 }
00485 
00486 const char *Token::chrInFirstWord(const char *str, char c)
00487 {
00488     for (;;) {
00489         if (*str == ' ' || *str == 0)
00490             return 0;
00491 
00492         if (*str == c)
00493             return str;
00494 
00495         ++str;
00496     }
00497 }
00498 
00499 int Token::firstWordLen(const char *str)
00500 {
00501     int len = 0;
00502     for (;;) {
00503         if (*str == ' ' || *str == 0)
00504             break;
00505 
00506         ++len;
00507         ++str;
00508     }
00509 
00510     return len;
00511 }
00512 
00513 #define multicompare(p,cond,ismulticomp)        \
00514 {                                               \
00515     if (!(cond)) {                              \
00516         if (*(p) != '|')                        \
00517             return false;                       \
00518         ++(p);                                  \
00519         ismulticomp = (*(p) && *(p) != ' ');    \
00520         continue;                               \
00521     }                                           \
00522     if (*(p) == '|') {                          \
00523         while (*(p) && *(p) != ' ')             \
00524             ++(p);                              \
00525     }                                           \
00526     ismulticomp = false;                        \
00527 }
00528 
00529 bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
00530 {
00531     const char *p = pattern;
00532     bool ismulticomp = false;
00533     while (*p) {
00534         // Skip spaces in pattern..
00535         while (*p == ' ')
00536             ++p;
00537 
00538         // No token => Success!
00539         if (*p == '\0')
00540             break;
00541 
00542         if (!tok) {
00543             // If we have no tokens, pattern "!!else" should return true
00544             if (p[0] == '!' && p[1] == '!' && p[2] != '\0') {
00545                 while (*p && *p != ' ')
00546                     ++p;
00547                 continue;
00548             } else
00549                 return false;
00550         }
00551 
00552         // Compare the first character of the string for optimization reasons
00553         // before doing more detailed checks.
00554         if (p[0] == '%') {
00555             ++p;
00556             switch (p[0]) {
00557             case '\0':
00558             case ' ':
00559             case '|':
00560                 //simple '%' character
00561             {
00562                 multicompare(p, tok->str() == "%", ismulticomp);
00563             }
00564             break;
00565             case 'v':
00566                 // TODO: %var% should match only for
00567                 // variables that have varId != 0, but that needs a lot of
00568                 // work, before that change can be made.
00569                 // Any symbolname..
00570                 if (p[3] == '%') { // %var%
00571                     p += 4;
00572                     multicompare(p,tok->isName(),ismulticomp);
00573                 } else { // %varid%
00574                     if (varid == 0) {
00575                         throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
00576                     }
00577 
00578                     if (tok->varId() != varid)
00579                         return false;
00580 
00581                     p += 6;
00582                 }
00583                 break;
00584             case 't':
00585                 // Type (%type%)
00586             {
00587                 p += 5;
00588                 multicompare(p,tok->isName() && tok->varId() == 0 && tok->str() != "delete",ismulticomp);
00589             }
00590             break;
00591             case 'a':
00592                 // Accept any token (%any%)
00593             {
00594                 p += 4;
00595                 if (p[0] == '|') {
00596                     while (*p && *p != ' ')
00597                         ++p;
00598                 }
00599                 ismulticomp = false;
00600             }
00601             break;
00602             case 'n':
00603                 // Number (%num%)
00604             {
00605                 p += 4;
00606                 multicompare(p,tok->isNumber(),ismulticomp);
00607             }
00608             break;
00609             case 'c': {
00610                 p += 1;
00611                 // Character (%char%)
00612                 if (p[0] == 'h') {
00613                     p += 4;
00614                     multicompare(p,tok->type() == eChar,ismulticomp);
00615                 }
00616                 // Const operator (%cop%)
00617                 else if (p[1] == 'p') {
00618                     p += 3;
00619                     multicompare(p,tok->isConstOp(),ismulticomp);
00620                 }
00621                 // Comparison operator (%comp%)
00622                 else {
00623                     p += 4;
00624                     multicompare(p,tok->isComparisonOp(),ismulticomp);
00625                 }
00626             }
00627             break;
00628             case 's':
00629                 // String (%str%)
00630             {
00631                 p += 4;
00632                 multicompare(p,tok->type() == eString,ismulticomp);
00633             }
00634             break;
00635             case 'b':
00636                 // Bool (%bool%)
00637             {
00638                 p += 5;
00639                 multicompare(p,tok->isBoolean(),ismulticomp);
00640             }
00641             break;
00642             case 'o': {
00643                 ++p;
00644                 if (p[1] == '%') {
00645                     // Op (%op%)
00646                     if (p[0] == 'p') {
00647                         p += 2;
00648                         multicompare(p,tok->isOp(),ismulticomp);
00649                     }
00650                     // Or (%or%)
00651                     else {
00652                         p += 2;
00653                         multicompare(p,tok->str() == "|",ismulticomp)
00654                     }
00655                 }
00656 
00657                 // Oror (%oror%)
00658                 else {
00659                     p += 4;
00660                     multicompare(p,tok->str() == "||",ismulticomp);
00661                 }
00662             }
00663             break;
00664             default:
00665                 //unknown %cmd%, abort
00666                 std::abort();
00667             }
00668         }
00669 
00670         else if (ismulticomp) {
00671             ismulticomp = false;
00672             continue;
00673         }
00674 
00675         // [.. => search for a one-character token..
00676         else if (p[0] == '[' && chrInFirstWord(p, ']')) {
00677             if (tok->str().length() != 1)
00678                 return false;
00679 
00680             const char *temp = p+1;
00681             bool chrFound = false;
00682             unsigned int count = 0;
00683             while (*temp && *temp != ' ') {
00684                 if (*temp == ']') {
00685                     ++count;
00686                 }
00687 
00688                 else if (*temp == tok->str()[0]) {
00689                     chrFound = true;
00690                     break;
00691                 }
00692 
00693                 ++temp;
00694             }
00695 
00696             if (count > 1 && tok->str()[0] == ']')
00697                 chrFound = true;
00698 
00699             if (!chrFound)
00700                 return false;
00701 
00702             p = temp;
00703             while (*p && *p != ' ')
00704                 ++p;
00705         }
00706 
00707         // Parse multi options, such as void|int|char (accept token which is one of these 3)
00708         else if (chrInFirstWord(p, '|') && (p[0] != '|' || firstWordLen(p) > 2)) {
00709             int res = multiCompare(tok, p, tok->_str.c_str());
00710             if (res == 0) {
00711                 // Empty alternative matches, use the same token on next round
00712                 while (*p && *p != ' ')
00713                     ++p;
00714                 continue;
00715             } else if (res == -1) {
00716                 // No match
00717                 return false;
00718             }
00719         }
00720 
00721         // Parse "not" options. Token can be anything except the given one
00722         else if (p[0] == '!' && p[1] == '!' && p[2] != '\0') {
00723             p += 2;
00724             if (firstWordEquals(p, tok->str().c_str()))
00725                 return false;
00726             while (*p && *p != ' ')
00727                 ++p;
00728         }
00729 
00730         else if (!firstWordEquals(p, tok->_str.c_str())) {
00731             return false;
00732         }
00733 
00734         while (*p && *p != ' ')
00735             ++p;
00736 
00737         tok = tok->next();
00738     }
00739 
00740     // The end of the pattern has been reached and nothing wrong has been found
00741     return true;
00742 }
00743 
00744 std::size_t Token::getStrLength(const Token *tok)
00745 {
00746     assert(tok != NULL);
00747 
00748     std::size_t len = 0;
00749     const std::string strValue(tok->strValue());
00750     const char *str = strValue.c_str();
00751 
00752     while (*str) {
00753         if (*str == '\\') {
00754             ++str;
00755 
00756             // string ends at '\0'
00757             if (*str == '0')
00758                 break;
00759         }
00760 
00761         ++str;
00762         ++len;
00763     }
00764 
00765     return len;
00766 }
00767 
00768 std::string Token::getCharAt(const Token *tok, std::size_t index)
00769 {
00770     assert(tok != NULL);
00771 
00772     const std::string strValue(tok->strValue());
00773     const char *str = strValue.c_str();
00774 
00775     while (*str) {
00776         if (index == 0) {
00777             std::string ret;
00778             if (*str == '\\') {
00779                 ret = *str;
00780                 ++str;
00781             }
00782             ret += *str;
00783             return ret;
00784         }
00785 
00786         if (*str == '\\')
00787             ++str;
00788         ++str;
00789         --index;
00790     }
00791     assert(index == 0);
00792 
00793     return "\\0";
00794 }
00795 
00796 void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation)
00797 {
00798     /**[newLocation] -> b -> c -> [srcStart] -> [srcEnd] -> f */
00799 
00800     // Fix the gap, which tokens to be moved will leave
00801     srcStart->previous()->next(srcEnd->next());
00802     srcEnd->next()->previous(srcStart->previous());
00803 
00804     // Fix the tokens to be moved
00805     srcEnd->next(newLocation->next());
00806     srcStart->previous(newLocation);
00807 
00808     // Fix the tokens at newLocation
00809     newLocation->next()->previous(srcEnd);
00810     newLocation->next(srcStart);
00811 
00812     // Update _progressValue
00813     for (Token *tok = srcStart; tok != srcEnd->next(); tok = tok->next())
00814         tok->_progressValue = newLocation->_progressValue;
00815 }
00816 
00817 Token* Token::nextArgument() const
00818 {
00819     for (const Token* tok = this; tok; tok = tok->next()) {
00820         if (tok->str() == ",")
00821             return tok->next();
00822         else if (tok->str() == "(" || tok->str() == "{" || tok->str() == "[")
00823             tok = tok->link();
00824         else if (tok->str() == "<" && tok->link())
00825             tok = tok->link();
00826         else if (tok->str() == ")" || tok->str() == ";")
00827             return 0;
00828     }
00829     return 0;
00830 }
00831 
00832 bool Token::findClosingBracket(const Token*& closing) const
00833 {
00834     if (_str == "<") {
00835         unsigned int depth = 0;
00836         for (closing = this; closing != NULL; closing = closing->next()) {
00837             if (closing->str() == "{" || closing->str() == "[" || closing->str() == "(")
00838                 closing = closing->link();
00839             else if (closing->str() == "}" || closing->str() == "]" || closing->str() == ")" || closing->str() == ";" || closing->str() == "=")
00840                 return false;
00841             else if (closing->str() == "<")
00842                 ++depth;
00843             else if (closing->str() == ">") {
00844                 if (--depth == 0)
00845                     return true;
00846             } else if (closing->str() == ">>") {
00847                 if (--depth == 0)
00848                     return true;
00849                 if (--depth == 0)
00850                     return true;
00851             }
00852         }
00853     }
00854 
00855     return false;
00856 }
00857 
00858 //---------------------------------------------------------------------------
00859 
00860 const Token *Token::findsimplematch(const Token *tok, const char pattern[])
00861 {
00862     for (; tok; tok = tok->next()) {
00863         if (Token::simpleMatch(tok, pattern))
00864             return tok;
00865     }
00866     return 0;
00867 }
00868 
00869 const Token *Token::findsimplematch(const Token *tok, const char pattern[], const Token *end)
00870 {
00871     for (; tok && tok != end; tok = tok->next()) {
00872         if (Token::simpleMatch(tok, pattern))
00873             return tok;
00874     }
00875     return 0;
00876 }
00877 
00878 const Token *Token::findmatch(const Token *tok, const char pattern[], unsigned int varId)
00879 {
00880     for (; tok; tok = tok->next()) {
00881         if (Token::Match(tok, pattern, varId))
00882             return tok;
00883     }
00884     return 0;
00885 }
00886 
00887 const Token *Token::findmatch(const Token *tok, const char pattern[], const Token *end, unsigned int varId)
00888 {
00889     for (; tok && tok != end; tok = tok->next()) {
00890         if (Token::Match(tok, pattern, varId))
00891             return tok;
00892     }
00893     return 0;
00894 }
00895 
00896 void Token::insertToken(const std::string &tokenStr, bool prepend)
00897 {
00898     Token *newToken;
00899 
00900     //TODO: Find a solution for the first token on the list
00901     if (prepend && !this->previous())
00902         return;
00903 
00904     if (_str.empty())
00905         newToken = this;
00906     else
00907         newToken = new Token(tokensBack);
00908     newToken->str(tokenStr);
00909     newToken->_linenr = _linenr;
00910     newToken->_fileIndex = _fileIndex;
00911     newToken->_progressValue = _progressValue;
00912 
00913     if (newToken != this) {
00914         if (prepend) {
00915             /*if (this->previous())*/ {
00916                 newToken->previous(this->previous());
00917                 newToken->previous()->next(newToken);
00918             } /*else if (tokensFront?) {
00919                 *tokensFront? = newToken;
00920             }*/
00921             this->previous(newToken);
00922             newToken->next(this);
00923         } else {
00924             if (this->next()) {
00925                 newToken->next(this->next());
00926                 newToken->next()->previous(newToken);
00927             } else if (tokensBack) {
00928                 *tokensBack = newToken;
00929             }
00930             this->next(newToken);
00931             newToken->previous(this);
00932         }
00933     }
00934 }
00935 
00936 void Token::eraseTokens(Token *begin, const Token *end)
00937 {
00938     if (!begin || begin == end)
00939         return;
00940 
00941     while (begin->next() && begin->next() != end) {
00942         begin->deleteNext();
00943     }
00944 }
00945 
00946 void Token::createMutualLinks(Token *begin, Token *end)
00947 {
00948     assert(begin != NULL);
00949     assert(end != NULL);
00950     assert(begin != end);
00951     begin->link(end);
00952     end->link(begin);
00953 }
00954 
00955 void Token::printOut(const char *title) const
00956 {
00957     if (title)
00958         std::cout << "\n### " << title << " ###\n";
00959     std::cout << stringifyList(true, true, true, true, true, 0, 0) << std::endl;
00960 }
00961 
00962 void Token::printOut(const char *title, const std::vector<std::string> &fileNames) const
00963 {
00964     if (title)
00965         std::cout << "\n### " << title << " ###\n";
00966     std::cout << stringifyList(true, true, true, true, true, &fileNames, 0) << std::endl;
00967 }
00968 
00969 void Token::stringify(std::ostream& os, bool varid, bool attributes) const
00970 {
00971     if (attributes) {
00972         if (isUnsigned())
00973             os << "unsigned ";
00974         else if (isSigned())
00975             os << "signed ";
00976         if (isLong())
00977             os << "long ";
00978     }
00979     if (_str[0] != '\"' || _str.find("\0") == std::string::npos)
00980         os << _str;
00981     else {
00982         for (std::size_t i = 0U; i < _str.size(); ++i) {
00983             if (_str[i] == '\0')
00984                 os << "\\0";
00985             else
00986                 os << _str[i];
00987         }
00988     }
00989     if (varid && _varId != 0)
00990         os << '@' << _varId;
00991 }
00992 
00993 std::string Token::stringifyList(bool varid, bool attributes, bool linenumbers, bool linebreaks, bool files, const std::vector<std::string>* fileNames, const Token* end) const
00994 {
00995     if (this == end)
00996         return "";
00997 
00998     std::ostringstream ret;
00999 
01000     unsigned int lineNumber = _linenr;
01001     int fileInd = files ? -1 : static_cast<int>(_fileIndex);
01002     std::map<int, unsigned int> lineNumbers;
01003     for (const Token *tok = this; tok != end; tok = tok->next()) {
01004         bool fileChange = false;
01005         if (static_cast<int>(tok->_fileIndex) != fileInd) {
01006             if (fileInd != -1) {
01007                 lineNumbers[fileInd] = tok->_fileIndex;
01008             }
01009 
01010             fileInd = static_cast<int>(tok->_fileIndex);
01011             if (files) {
01012                 ret << "\n\n##file ";
01013                 if (fileNames && fileNames->size() > tok->_fileIndex)
01014                     ret << fileNames->at(tok->_fileIndex);
01015                 else
01016                     ret << fileInd;
01017             }
01018 
01019             lineNumber = lineNumbers[fileInd];
01020             fileChange = true;
01021         }
01022 
01023         if (linebreaks && (lineNumber != tok->linenr() || fileChange)) {
01024             if (lineNumber+4 < tok->linenr() && fileInd == static_cast<int>(tok->_fileIndex)) {
01025                 ret << '\n' << lineNumber+1 << ":\n|\n";
01026                 ret << tok->linenr()-1 << ":\n";
01027                 ret << tok->linenr() << ": ";
01028             } else {
01029                 while (lineNumber < tok->linenr()) {
01030                     ++lineNumber;
01031                     ret << '\n';
01032                     if (linenumbers) {
01033                         ret << lineNumber << ':';
01034                         if (lineNumber == tok->linenr())
01035                             ret << ' ';
01036                     }
01037                 }
01038             }
01039             lineNumber = tok->linenr();
01040         }
01041 
01042         tok->stringify(ret, varid, attributes); // print token
01043         if (tok->next() != end && (!linebreaks || (tok->next()->linenr() <= tok->linenr() && tok->next()->fileIndex() == tok->fileIndex())))
01044             ret << ' ';
01045     }
01046     if (linebreaks && files)
01047         ret << '\n';
01048     return ret.str();
01049 }
01050 
01051 std::string Token::stringifyList(const Token* end, bool attributes) const
01052 {
01053     return stringifyList(false, attributes, false, false, false, 0, end);
01054 }
01055 
01056 std::string Token::stringifyList(bool varid) const
01057 {
01058     return stringifyList(varid, false, true, true, true, 0, 0);
01059 }
01060 
01061 void Token::astOperand1(Token *tok)
01062 {
01063     // goto parent operator
01064     while (tok->_astParent)
01065         tok = tok->_astParent;
01066     tok->_astParent = this;
01067     _astOperand1 = tok;
01068 }
01069 
01070 void Token::astOperand2(Token *tok)
01071 {
01072     // goto parent operator
01073     while (tok->_astParent)
01074         tok = tok->_astParent;
01075     tok->_astParent = this;
01076     _astOperand2 = tok;
01077 }
01078 
01079 void Token::astFunctionCall()
01080 {
01081     _astOperand1 = _next;
01082     _next->_astParent = this;
01083 }
01084 
01085 void Token::astHandleParentheses()
01086 {
01087     // Assumptions:
01088     // * code is valid
01089     // * _str is one of: ( ) ]
01090 
01091     Token *innerTop;
01092     if (Token::Match(this, ")|]"))
01093         innerTop = _previous;
01094     else if (_next && _next->_str == ")")
01095         return;
01096     else  // _str = "("
01097         innerTop = _next;
01098     while (innerTop->_astParent)
01099         innerTop = innerTop->_astParent;
01100 
01101     if (_astParent) {
01102         if (_str == "(" && _astParent->_astOperand2 != NULL)
01103             _astParent->_astOperand2 = innerTop;
01104         else
01105             _astParent->_astOperand1 = innerTop;
01106         innerTop->_astParent = _astParent;
01107     } else {
01108         _astParent = innerTop;
01109     }
01110 }
01111