|
Cppcheck
|
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
1.7.6.1