2012-05-05 18:33:26 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2014-02-15 07:45:39 +01:00
* Copyright ( C ) 2007 - 2014 Daniel Marjamäki and Cppcheck team .
2012-05-05 18:33:26 +02:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "tokenlist.h"
# include "token.h"
# include "mathlib.h"
# include "path.h"
# include "preprocessor.h"
# include "settings.h"
2012-05-06 10:17:15 +02:00
# include "errorlogger.h"
2012-05-05 18:33:26 +02:00
# include <cstring>
# include <sstream>
# include <cctype>
# include <stack>
2014-04-15 06:31:09 +02:00
// How many compileExpression recursions are allowed?
// For practical code this could be endless. But in some special torture test
// there needs to be a limit.
static const unsigned int AST_MAX_DEPTH = 50U ;
2012-05-05 18:33:26 +02:00
TokenList : : TokenList ( const Settings * settings ) :
_front ( 0 ) ,
_back ( 0 ) ,
_settings ( settings )
{
}
TokenList : : ~ TokenList ( )
{
deallocateTokens ( ) ;
}
//---------------------------------------------------------------------------
// Deallocate lists..
void TokenList : : deallocateTokens ( )
{
deleteTokens ( _front ) ;
_front = 0 ;
_back = 0 ;
_files . clear ( ) ;
}
2014-01-28 17:15:07 +01:00
unsigned int TokenList : : appendFileIfNew ( const std : : string & fileName )
{
// Has this file been tokenized already?
for ( unsigned int i = 0 ; i < _files . size ( ) ; + + i )
if ( Path : : sameFileName ( _files [ i ] , fileName ) )
return i ;
// The "_files" vector remembers what files have been tokenized..
2014-04-02 13:56:34 +02:00
_files . push_back ( Path : : simplifyPath ( fileName ) ) ;
2014-01-28 17:15:07 +01:00
return static_cast < unsigned int > ( _files . size ( ) - 1 ) ;
}
2012-05-05 18:33:26 +02:00
void TokenList : : deleteTokens ( Token * tok )
{
while ( tok ) {
Token * next = tok - > next ( ) ;
delete tok ;
tok = next ;
}
}
//---------------------------------------------------------------------------
// add a token.
//---------------------------------------------------------------------------
2014-03-09 17:54:49 +01:00
void TokenList : : addtoken ( const std : : string & str , const unsigned int lineno , const unsigned int fileno , bool split )
2012-05-05 18:33:26 +02:00
{
2014-03-09 17:54:49 +01:00
if ( str . empty ( ) )
2012-05-05 18:33:26 +02:00
return ;
// If token contains # characters, split it up
2014-03-09 17:54:49 +01:00
if ( split ) {
size_t begin = 0 ;
size_t end = 0 ;
while ( ( end = str . find ( " ## " , begin ) ) ! = std : : string : : npos ) {
addtoken ( str . substr ( begin , end - begin ) , lineno , fileno , false ) ;
addtoken ( " ## " , lineno , fileno , false ) ;
begin = end + 2 ;
}
if ( begin ! = 0 ) {
addtoken ( str . substr ( begin ) , lineno , fileno , false ) ;
return ;
2012-05-05 18:33:26 +02:00
}
}
// Replace hexadecimal value with decimal
2014-03-09 17:54:49 +01:00
std : : string str2 ;
2012-09-10 21:13:32 +02:00
if ( MathLib : : isHex ( str ) | | MathLib : : isOct ( str ) | | MathLib : : isBin ( str ) ) {
2014-03-09 17:54:49 +01:00
std : : ostringstream str2stream ;
str2stream < < MathLib : : toLongNumber ( str ) ;
str2 = str2stream . str ( ) ;
} else if ( str . compare ( 0 , 5 , " _Bool " ) = = 0 ) {
str2 = " bool " ;
2012-05-05 18:33:26 +02:00
} else {
2014-03-09 17:54:49 +01:00
str2 = str ;
2012-05-05 18:33:26 +02:00
}
if ( _back ) {
2014-03-09 17:54:49 +01:00
_back - > insertToken ( str2 ) ;
2012-05-05 18:33:26 +02:00
} else {
_front = new Token ( & _back ) ;
_back = _front ;
2014-03-09 17:54:49 +01:00
_back - > str ( str2 ) ;
2012-05-05 18:33:26 +02:00
}
_back - > linenr ( lineno ) ;
_back - > fileIndex ( fileno ) ;
}
void TokenList : : addtoken ( const Token * tok , const unsigned int lineno , const unsigned int fileno )
{
if ( tok = = 0 )
return ;
if ( _back ) {
2013-09-24 06:43:03 +02:00
_back - > insertToken ( tok - > str ( ) , tok - > originalName ( ) ) ;
2012-05-05 18:33:26 +02:00
} else {
_front = new Token ( & _back ) ;
_back = _front ;
_back - > str ( tok - > str ( ) ) ;
2013-09-24 06:43:03 +02:00
_back - > originalName ( tok - > originalName ( ) ) ;
2012-05-05 18:33:26 +02:00
}
_back - > linenr ( lineno ) ;
_back - > fileIndex ( fileno ) ;
2014-05-06 06:35:48 +02:00
_back - > flags ( tok - > flags ( ) ) ;
2012-05-05 18:33:26 +02:00
}
//---------------------------------------------------------------------------
// InsertTokens - Copy and insert tokens
//---------------------------------------------------------------------------
void TokenList : : insertTokens ( Token * dest , const Token * src , unsigned int n )
{
std : : stack < Token * > link ;
while ( n > 0 ) {
2013-09-24 06:43:03 +02:00
dest - > insertToken ( src - > str ( ) , src - > originalName ( ) ) ;
2012-05-05 18:33:26 +02:00
dest = dest - > next ( ) ;
// Set links
if ( Token : : Match ( dest , " (|[|{ " ) )
link . push ( dest ) ;
else if ( ! link . empty ( ) & & Token : : Match ( dest , " )|]|} " ) ) {
Token : : createMutualLinks ( dest , link . top ( ) ) ;
link . pop ( ) ;
}
dest - > fileIndex ( src - > fileIndex ( ) ) ;
dest - > linenr ( src - > linenr ( ) ) ;
dest - > varId ( src - > varId ( ) ) ;
dest - > type ( src - > type ( ) ) ;
2014-05-06 06:35:48 +02:00
dest - > flags ( src - > flags ( ) ) ;
2012-05-05 18:33:26 +02:00
src = src - > next ( ) ;
- - n ;
}
}
//---------------------------------------------------------------------------
// Tokenize - tokenizes a given file.
//---------------------------------------------------------------------------
bool TokenList : : createTokens ( std : : istream & code , const std : : string & file0 )
{
_files . push_back ( file0 ) ;
// line number in parsed code
unsigned int lineno = 1 ;
// The current token being parsed
std : : string CurrentToken ;
// lineNumbers holds line numbers for files in fileIndexes
// every time an include file is completely parsed, last item in the vector
// is removed and lineno is set to point to that value.
std : : stack < unsigned int > lineNumbers ;
// fileIndexes holds index for _files vector about currently parsed files
// every time an include file is completely parsed, last item in the vector
// is removed and FileIndex is set to point to that value.
std : : stack < unsigned int > fileIndexes ;
// FileIndex. What file in the _files vector is read now?
unsigned int FileIndex = 0 ;
bool expandedMacro = false ;
// Read one byte at a time from code and create tokens
2014-03-09 17:54:49 +01:00
for ( char ch = ( char ) code . get ( ) ; code . good ( ) & & ch ; ch = ( char ) code . get ( ) ) {
2012-05-05 18:33:26 +02:00
if ( ch = = Preprocessor : : macroChar ) {
while ( code . peek ( ) = = Preprocessor : : macroChar )
code . get ( ) ;
2014-01-03 18:53:37 +01:00
if ( ! CurrentToken . empty ( ) ) {
2014-03-09 17:54:49 +01:00
addtoken ( CurrentToken , lineno , FileIndex , true ) ;
2014-01-03 18:53:37 +01:00
_back - > isExpandedMacro ( expandedMacro ) ;
}
CurrentToken . clear ( ) ;
2012-05-05 18:33:26 +02:00
expandedMacro = true ;
2014-01-03 18:53:37 +01:00
continue ;
2012-05-05 18:33:26 +02:00
}
// char/string..
// multiline strings are not handled. The preprocessor should handle that for us.
else if ( ch = = ' \' ' | | ch = = ' \" ' ) {
std : : string line ;
// read char
bool special = false ;
char c = ch ;
do {
// Append token..
line + = c ;
// Special sequence '\.'
if ( special )
special = false ;
else
special = ( c = = ' \\ ' ) ;
// Get next character
c = ( char ) code . get ( ) ;
} while ( code . good ( ) & & ( special | | c ! = ch ) ) ;
line + = ch ;
// Handle #file "file.h"
if ( CurrentToken = = " #file " ) {
// Extract the filename
line = line . substr ( 1 , line . length ( ) - 2 ) ;
+ + lineno ;
fileIndexes . push ( FileIndex ) ;
2014-01-28 17:15:07 +01:00
FileIndex = appendFileIfNew ( line ) ;
2012-05-05 18:33:26 +02:00
lineNumbers . push ( lineno ) ;
lineno = 0 ;
} else {
// Add previous token
2014-03-09 17:54:49 +01:00
addtoken ( CurrentToken , lineno , FileIndex ) ;
2012-05-05 18:33:26 +02:00
if ( ! CurrentToken . empty ( ) )
2013-08-30 06:27:46 +02:00
_back - > isExpandedMacro ( expandedMacro ) ;
2012-05-05 18:33:26 +02:00
// Add content of the string
2014-03-09 17:54:49 +01:00
addtoken ( line , lineno , FileIndex ) ;
2012-05-05 18:33:26 +02:00
if ( ! line . empty ( ) )
2013-08-30 06:27:46 +02:00
_back - > isExpandedMacro ( expandedMacro ) ;
2012-05-05 18:33:26 +02:00
}
CurrentToken . clear ( ) ;
continue ;
}
if ( ch = = ' . ' & &
CurrentToken . length ( ) > 0 & &
std : : isdigit ( CurrentToken [ 0 ] ) ) {
// Don't separate doubles "5.4"
2012-12-27 11:51:12 +01:00
} else if ( std : : strchr ( " +- " , ch ) & &
2012-05-05 18:33:26 +02:00
CurrentToken . length ( ) > 0 & &
std : : isdigit ( CurrentToken [ 0 ] ) & &
( CurrentToken [ CurrentToken . length ( ) - 1 ] = = ' e ' | |
CurrentToken [ CurrentToken . length ( ) - 1 ] = = ' E ' ) & &
! MathLib : : isHex ( CurrentToken ) ) {
// Don't separate doubles "4.2e+10"
} else if ( CurrentToken . empty ( ) & & ch = = ' . ' & & std : : isdigit ( code . peek ( ) ) ) {
// tokenize .125 into 0.125
CurrentToken = " 0 " ;
2012-12-27 11:51:12 +01:00
} else if ( std : : strchr ( " +-*/%&|^?!=<>[]() { } ; : , . ~ \ n " , ch)) {
2012-05-05 18:33:26 +02:00
if ( CurrentToken = = " #file " ) {
// Handle this where strings are handled
continue ;
2012-12-27 16:52:31 +01:00
} else if ( CurrentToken = = " #line " ) {
// Read to end of line
std : : string line ;
std : : getline ( code , line ) ;
2013-01-23 18:27:28 +01:00
unsigned int row ;
2014-01-28 17:15:07 +01:00
std : : istringstream fiss ( line ) ;
if ( fiss > > row ) {
// Update the current line number
2013-01-23 18:27:28 +01:00
lineno = row ;
2014-01-28 17:15:07 +01:00
2014-01-29 03:16:29 +01:00
std : : string line2 ;
if ( std : : getline ( fiss , line2 ) & & line2 . length ( ) > 4U ) {
2014-01-28 17:15:07 +01:00
// _"file_name" -> file_name
2014-01-29 03:16:29 +01:00
line2 = line2 . substr ( 2 , line2 . length ( ) - 3 ) ;
2014-01-28 17:15:07 +01:00
// Update the current file
2014-01-29 03:16:29 +01:00
FileIndex = appendFileIfNew ( line2 ) ;
2014-01-28 17:15:07 +01:00
}
} else
+ + lineno ;
2012-12-27 16:52:31 +01:00
CurrentToken . clear ( ) ;
continue ;
2012-05-05 18:33:26 +02:00
} else if ( CurrentToken = = " #endfile " ) {
if ( lineNumbers . empty ( ) | | fileIndexes . empty ( ) ) { // error
deallocateTokens ( ) ;
return false ;
}
lineno = lineNumbers . top ( ) ;
lineNumbers . pop ( ) ;
FileIndex = fileIndexes . top ( ) ;
fileIndexes . pop ( ) ;
CurrentToken . clear ( ) ;
continue ;
}
2014-03-09 17:54:49 +01:00
addtoken ( CurrentToken , lineno , FileIndex , true ) ;
2014-01-03 18:53:37 +01:00
if ( ! CurrentToken . empty ( ) ) {
2013-08-30 06:27:46 +02:00
_back - > isExpandedMacro ( expandedMacro ) ;
2014-01-03 18:53:37 +01:00
expandedMacro = false ;
}
2012-05-05 18:33:26 +02:00
CurrentToken . clear ( ) ;
if ( ch = = ' \n ' ) {
2013-07-24 13:06:59 +02:00
if ( _settings - > terminated ( ) )
return false ;
2012-05-05 18:33:26 +02:00
+ + lineno ;
continue ;
} else if ( ch = = ' ' ) {
continue ;
}
CurrentToken + = ch ;
// Add "++", "--", ">>" or ... token
2012-12-27 11:51:12 +01:00
if ( std : : strchr ( " +-<>=:&| " , ch ) & & ( code . peek ( ) = = ch ) )
2012-05-05 18:33:26 +02:00
CurrentToken + = ( char ) code . get ( ) ;
2014-03-09 17:54:49 +01:00
addtoken ( CurrentToken , lineno , FileIndex ) ;
2013-08-30 06:27:46 +02:00
_back - > isExpandedMacro ( expandedMacro ) ;
2012-05-05 18:33:26 +02:00
CurrentToken . clear ( ) ;
2014-01-03 18:53:37 +01:00
expandedMacro = false ;
2012-05-05 18:33:26 +02:00
continue ;
}
CurrentToken + = ch ;
}
2014-03-09 17:54:49 +01:00
addtoken ( CurrentToken , lineno , FileIndex , true ) ;
2012-05-05 18:33:26 +02:00
if ( ! CurrentToken . empty ( ) )
2013-08-30 06:27:46 +02:00
_back - > isExpandedMacro ( expandedMacro ) ;
2012-05-05 18:33:26 +02:00
_front - > assignProgressValues ( ) ;
for ( unsigned int i = 1 ; i < _files . size ( ) ; i + + )
_files [ i ] = Path : : getRelativePath ( _files [ i ] , _settings - > _basePaths ) ;
return true ;
}
//---------------------------------------------------------------------------
2013-11-11 16:39:34 +01:00
static bool iscast ( const Token * tok )
{
if ( ! Token : : Match ( tok , " ( %var% " ) )
return false ;
2014-05-17 12:09:32 +02:00
if ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) )
return false ;
2014-05-04 18:36:04 +02:00
if ( Token : : Match ( tok , " ( (| typeof ( " ) & & Token : : Match ( tok - > link ( ) , " ) %num% " ) )
return true ;
2013-11-11 16:39:34 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2014-04-15 15:46:26 +02:00
if ( tok2 - > str ( ) = = " ) " )
return tok2 - > previous ( ) - > str ( ) = = " * " | |
( Token : : Match ( tok2 , " ) %any% " ) & &
2014-04-27 18:03:50 +02:00
( ! tok2 - > next ( ) - > isOp ( ) & & ! Token : : Match ( tok2 - > next ( ) , " [[]);,?:.] " ) ) ) ;
2013-12-25 21:19:28 +01:00
if ( ! Token : : Match ( tok2 , " %var%|*|&|:: " ) )
2014-04-15 15:46:26 +02:00
return false ;
2013-11-11 16:39:34 +01:00
}
return false ;
}
2014-04-15 06:16:47 +02:00
static void compileUnaryOp ( Token * & tok , void ( * f ) ( Token * & , std : : stack < Token * > & , unsigned int depth ) , std : : stack < Token * > & op , unsigned int depth )
2012-12-15 20:21:09 +01:00
{
2013-11-04 11:26:16 +01:00
Token * unaryop = tok ;
2014-05-17 12:09:32 +02:00
if ( f ) {
tok = tok - > next ( ) ;
f ( tok , op , depth ) ;
}
2013-11-04 11:26:16 +01:00
if ( ! op . empty ( ) ) {
unaryop - > astOperand1 ( op . top ( ) ) ;
op . pop ( ) ;
}
op . push ( unaryop ) ;
}
2014-04-15 06:16:47 +02:00
static void compileBinOp ( Token * & tok , void ( * f ) ( Token * & , std : : stack < Token * > & , unsigned int depth ) , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
Token * binop = tok ;
2014-05-17 12:09:32 +02:00
if ( f ) {
tok = tok - > next ( ) ;
if ( tok )
f ( tok , op , depth ) ;
}
2014-05-03 12:08:42 +02:00
2013-11-04 11:26:16 +01:00
// TODO: Should we check if op is empty.
// * Is it better to add assertion that it isn't?
// * Write debug warning if it's empty?
if ( ! op . empty ( ) ) {
binop - > astOperand2 ( op . top ( ) ) ;
op . pop ( ) ;
}
if ( ! op . empty ( ) ) {
binop - > astOperand1 ( op . top ( ) ) ;
op . pop ( ) ;
}
op . push ( binop ) ;
}
2013-03-02 15:49:48 +01:00
2014-04-15 06:16:47 +02:00
static void compileExpression ( Token * & tok , std : : stack < Token * > & op , unsigned int depth ) ;
2013-11-04 11:26:16 +01:00
2014-04-15 06:16:47 +02:00
static void compileTerm ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2013-11-11 16:39:34 +01:00
if ( ! tok )
return ;
2013-11-20 05:57:56 +01:00
if ( Token : : Match ( tok , " L %str%|%char% " ) )
tok = tok - > next ( ) ;
2013-11-04 11:26:16 +01:00
if ( tok - > isLiteral ( ) ) {
op . push ( tok ) ;
tok = tok - > next ( ) ;
2013-11-11 16:39:34 +01:00
} else if ( tok - > str ( ) = = " return " ) {
2014-04-15 06:16:47 +02:00
compileUnaryOp ( tok , compileExpression , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else if ( tok - > isName ( ) ) {
2014-05-17 12:09:32 +02:00
while ( tok - > next ( ) & & tok - > next ( ) - > isName ( ) )
2013-11-04 11:26:16 +01:00
tok = tok - > next ( ) ;
2014-05-17 12:09:32 +02:00
op . push ( tok ) ;
if ( tok - > next ( ) & & tok - > linkAt ( 1 ) & & Token : : Match ( tok , " %var% < " ) )
tok = tok - > linkAt ( 1 ) ;
tok = tok - > next ( ) ;
2014-02-05 06:05:48 +01:00
} else if ( tok - > str ( ) = = " { " ) {
op . push ( tok ) ;
tok = tok - > link ( ) - > next ( ) ;
2012-12-15 20:21:09 +01:00
}
2013-11-04 11:26:16 +01:00
}
2012-12-15 20:21:09 +01:00
2014-04-15 06:16:47 +02:00
static void compileScope ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileTerm ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " :: " ) {
2014-02-25 06:36:10 +01:00
if ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) )
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileTerm , op , depth ) ;
2014-02-25 06:36:10 +01:00
else
2014-05-17 12:09:32 +02:00
compileUnaryOp ( tok , compileTerm , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
2012-12-16 10:06:55 +01:00
}
2013-11-04 11:26:16 +01:00
}
2014-05-17 12:09:32 +02:00
static bool isPrefixUnary ( const Token * tok )
2013-11-25 20:58:40 +01:00
{
2014-05-17 12:09:32 +02:00
if ( ! tok - > previous ( )
| | ( Token : : Match ( tok - > previous ( ) , " (|[|{|%op%|;|}|?|:|, " )
& & ( tok - > previous ( ) - > type ( ) ! = Token : : eIncDecOp | | tok - > type ( ) = = Token : : eIncDecOp ) ) )
return true ;
return tok - > strAt ( - 1 ) = = " ) " & & iscast ( tok - > linkAt ( - 1 ) ) ;
2014-05-08 06:48:53 +02:00
}
2014-05-17 12:09:32 +02:00
static void compilePrecedence2 ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2014-05-08 06:48:53 +02:00
{
2014-05-17 12:09:32 +02:00
compileScope ( tok , op , depth ) ;
2014-05-08 06:48:53 +02:00
while ( tok ) {
2014-05-17 12:09:32 +02:00
if ( tok - > type ( ) = = Token : : eIncDecOp & & ! isPrefixUnary ( tok ) ) {
compileUnaryOp ( tok , compileScope , op , depth ) ;
} else if ( tok - > str ( ) = = " . " ) {
2014-04-29 06:09:26 +02:00
compileBinOp ( tok , compileScope , op , depth ) ;
2014-05-08 06:48:53 +02:00
} else if ( tok - > str ( ) = = " [ " ) {
2014-05-17 12:09:32 +02:00
Token * tok2 = tok ;
compileBinOp ( tok , compileExpression , op , depth ) ;
tok = tok2 - > link ( ) - > next ( ) ;
} else if ( tok - > str ( ) = = " ( " & & ( ! iscast ( tok ) | | Token : : Match ( tok - > previous ( ) , " if|while|for|switch|catch " ) ) ) {
Token * tok2 = tok ;
2014-04-29 06:09:26 +02:00
tok = tok - > next ( ) ;
2014-05-17 12:09:32 +02:00
compileExpression ( tok , op , depth ) ;
tok = tok2 ;
if ( ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) & & ! Token : : Match ( tok - > previous ( ) , " return|throw " ) )
| | tok - > strAt ( - 1 ) = = " ] "
| | ( tok - > strAt ( - 1 ) = = " > " & & tok - > linkAt ( - 1 ) )
| | ( tok - > strAt ( - 1 ) = = " ) " & & ! iscast ( tok - > linkAt ( - 1 ) ) ) ) { // Don't treat brackets to clarify precedence as function calls
if ( tok - > strAt ( 1 ) ! = " ) " )
compileBinOp ( tok , 0 , op , depth ) ;
else
compileUnaryOp ( tok , 0 , op , depth ) ;
}
tok = tok - > link ( ) - > next ( ) ;
2013-11-25 20:58:40 +01:00
} else break ;
}
}
2014-05-17 12:09:32 +02:00
static void compilePrecedence3 ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
{
compilePrecedence2 ( tok , op , depth ) ;
while ( tok ) {
if ( ( Token : : Match ( tok , " [+-!~*&] " ) | | tok - > type ( ) = = Token : : eIncDecOp ) & &
isPrefixUnary ( tok ) ) {
compileUnaryOp ( tok , compilePrecedence3 , op , depth ) ;
} else if ( tok - > str ( ) = = " ( " & & iscast ( tok ) ) {
Token * tok2 = tok ;
tok = tok - > link ( ) - > next ( ) ;
compilePrecedence3 ( tok , op , depth ) ;
compileUnaryOp ( tok2 , 0 , op , depth ) ;
}
// TODO: Handle sizeof, new and delete
else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileMulDiv ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-05-17 12:09:32 +02:00
compilePrecedence3 ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " [*/%] " ) ) {
2014-04-26 13:32:08 +02:00
if ( Token : : Match ( tok , " * [*,)] " ) ) {
2014-05-17 12:09:32 +02:00
Token * tok2 = tok ;
while ( tok2 - > next ( ) & & tok2 - > str ( ) = = " * " )
tok2 = tok2 - > next ( ) ;
if ( Token : : Match ( tok2 , " [,)] " ) ) {
//tok = tok2->next();
break ;
}
2014-04-26 13:32:08 +02:00
}
2014-05-17 12:09:32 +02:00
compileBinOp ( tok , compilePrecedence3 , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileAddSub ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileMulDiv ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " +|- " ) ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileMulDiv , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileShift ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileAddSub ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " <<|>> " ) ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileAddSub , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileRelComp ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileShift ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " <|<=|>=|> " ) ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileShift , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2012-12-16 10:06:55 +01:00
2014-04-15 06:16:47 +02:00
static void compileEqComp ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileRelComp ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " ==|!= " ) ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileRelComp , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileAnd ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileEqComp ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " & " ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileEqComp , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileXor ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileAnd ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " ^ " ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileAnd , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileOr ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileXor ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " | " ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileXor , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileLogicAnd ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileOr ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " && " ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileOr , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileLogicOr ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:16:47 +02:00
compileLogicAnd ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " || " ) {
2014-04-15 06:16:47 +02:00
compileBinOp ( tok , compileLogicAnd , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-05-11 13:39:28 +02:00
static void compileAssignTernary ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-05-11 13:39:28 +02:00
compileLogicOr ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2014-05-11 13:39:28 +02:00
// TODO: http://en.cppreference.com/w/cpp/language/operator_precedence says:
// "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
if ( tok - > isAssignmentOp ( ) | | Token : : Match ( tok , " [?:] " ) ) {
2014-05-17 12:09:32 +02:00
compileBinOp ( tok , compileAssignTernary , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileComma ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-05-11 13:39:28 +02:00
compileAssignTernary ( tok , op , depth ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " , " ) {
2014-05-11 13:39:28 +02:00
compileBinOp ( tok , compileAssignTernary , op , depth ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-04-15 06:16:47 +02:00
static void compileExpression ( Token * & tok , std : : stack < Token * > & op , unsigned int depth )
2013-11-04 11:26:16 +01:00
{
2014-04-15 06:31:09 +02:00
if ( depth > AST_MAX_DEPTH )
2014-04-13 12:47:54 +02:00
return ; // ticket #5592
2013-11-10 15:51:33 +01:00
if ( tok )
2014-04-15 06:16:47 +02:00
compileComma ( tok , op , depth + 1U ) ;
2013-11-04 11:26:16 +01:00
}
2014-01-27 06:18:42 +01:00
static Token * createAstAtToken ( Token * tok )
{
if ( Token : : simpleMatch ( tok , " for ( " ) ) {
Token * tok2 = tok - > tokAt ( 2 ) ;
2014-02-16 11:47:52 +01:00
Token * init1 = nullptr ;
2014-01-27 06:18:42 +01:00
const Token * const endPar = tok - > next ( ) - > link ( ) ;
while ( tok2 & & tok2 ! = endPar & & tok2 - > str ( ) ! = " ; " ) {
if ( tok2 - > str ( ) = = " < " & & tok2 - > link ( ) ) {
tok2 = tok2 - > link ( ) ;
if ( ! tok2 )
break ;
2014-05-11 13:37:53 +02:00
} else if ( Token : : Match ( tok2 , " %var% %op%|(|[|.|:|:: " ) | | Token : : Match ( tok2 - > previous ( ) , " [( ; { } ] % cop % | ( " )) {
2014-01-27 06:18:42 +01:00
init1 = tok2 ;
std : : stack < Token * > operands ;
2014-04-15 06:16:47 +02:00
compileExpression ( tok2 , operands , 0U ) ;
2014-01-27 06:18:42 +01:00
if ( tok2 - > str ( ) = = " ; " | | tok2 - > str ( ) = = " ) " )
break ;
init1 = 0 ;
2014-01-15 17:32:14 +01:00
}
2014-01-27 06:18:42 +01:00
tok2 = tok2 - > next ( ) ;
}
if ( ! tok2 | | tok2 - > str ( ) ! = " ; " ) {
if ( tok2 = = endPar & & init1 ) {
tok - > next ( ) - > astOperand2 ( init1 ) ;
tok - > next ( ) - > astOperand1 ( tok ) ;
2014-01-15 17:32:14 +01:00
}
2014-01-27 06:18:42 +01:00
return tok2 ;
}
2014-01-15 17:32:14 +01:00
2014-01-27 06:18:42 +01:00
Token * const init = init1 ? init1 : tok2 ;
2014-01-15 17:32:14 +01:00
2014-01-27 06:18:42 +01:00
Token * const semicolon1 = tok2 ;
tok2 = tok2 - > next ( ) ;
std : : stack < Token * > operands2 ;
2014-04-15 06:16:47 +02:00
compileExpression ( tok2 , operands2 , 0U ) ;
2014-01-27 06:18:42 +01:00
Token * const semicolon2 = tok2 ;
tok2 = tok2 - > next ( ) ;
std : : stack < Token * > operands3 ;
2014-04-15 06:16:47 +02:00
compileExpression ( tok2 , operands3 , 0U ) ;
2014-01-15 17:32:14 +01:00
2014-01-27 06:18:42 +01:00
if ( init ! = semicolon1 )
semicolon1 - > astOperand1 ( const_cast < Token * > ( init - > astTop ( ) ) ) ;
tok2 = semicolon1 - > next ( ) ;
while ( tok2 ! = semicolon2 & & ! tok2 - > isName ( ) & & ! tok2 - > isNumber ( ) )
2014-01-15 17:32:14 +01:00
tok2 = tok2 - > next ( ) ;
2014-01-27 06:18:42 +01:00
if ( tok2 ! = semicolon2 )
semicolon2 - > astOperand1 ( const_cast < Token * > ( tok2 - > astTop ( ) ) ) ;
tok2 = tok - > linkAt ( 1 ) ;
while ( tok2 ! = semicolon2 & & ! tok2 - > isName ( ) & & ! tok2 - > isNumber ( ) )
tok2 = tok2 - > previous ( ) ;
if ( tok2 ! = semicolon2 )
semicolon2 - > astOperand2 ( const_cast < Token * > ( tok2 - > astTop ( ) ) ) ;
semicolon1 - > astOperand2 ( semicolon2 ) ;
tok - > next ( ) - > astOperand1 ( tok ) ;
tok - > next ( ) - > astOperand2 ( semicolon1 ) ;
return tok - > linkAt ( 1 ) ;
}
2014-01-28 06:11:53 +01:00
if ( Token : : simpleMatch ( tok , " ( { " ) )
return tok ;
2014-02-17 17:37:39 +01:00
if ( Token : : Match ( tok , " %type% < " ) & & Token : : Match ( tok - > linkAt ( 1 ) , " > !!( " ) )
return tok - > linkAt ( 1 ) ;
2014-05-11 13:37:53 +02:00
if ( tok - > str ( ) = = " return " | | ! tok - > previous ( ) | | Token : : Match ( tok , " %var% %op%|(|[|.|:: " ) | | Token : : Match ( tok - > previous ( ) , " [;{}] %cop%|( !!{ " ) ) {
2014-01-27 06:18:42 +01:00
std : : stack < Token * > operands ;
Token * const tok1 = tok ;
2014-04-15 06:16:47 +02:00
compileExpression ( tok , operands , 0U ) ;
2014-01-27 06:18:42 +01:00
Token * const endToken = tok ;
2014-01-28 06:11:53 +01:00
if ( endToken = = tok1 )
return tok1 ;
2014-01-27 06:18:42 +01:00
// Compile inner expressions inside inner ({..})
2014-01-28 06:11:53 +01:00
for ( tok = tok1 - > next ( ) ; tok & & tok ! = endToken ; tok = tok ? tok - > next ( ) : NULL ) {
2014-01-27 06:18:42 +01:00
if ( ! Token : : simpleMatch ( tok , " ( { " ) )
continue ;
2014-01-28 06:11:53 +01:00
if ( tok - > next ( ) = = endToken )
break ;
2014-01-27 06:18:42 +01:00
const Token * const endToken2 = tok - > linkAt ( 1 ) ;
for ( ; tok & & tok ! = endToken & & tok ! = endToken2 ; tok = tok ? tok - > next ( ) : NULL )
tok = createAstAtToken ( tok ) ;
2012-12-15 20:21:09 +01:00
}
2014-01-27 06:18:42 +01:00
return endToken ? endToken - > previous ( ) : NULL ;
}
return tok ;
}
void TokenList : : createAst ( )
{
for ( Token * tok = _front ; tok ; tok = tok ? tok - > next ( ) : NULL ) {
tok = createAstAtToken ( tok ) ;
2012-12-15 20:21:09 +01:00
}
}
2012-05-05 18:33:26 +02:00
const std : : string & TokenList : : file ( const Token * tok ) const
{
return _files . at ( tok - > fileIndex ( ) ) ;
}
std : : string TokenList : : fileLine ( const Token * tok ) const
{
2012-05-06 10:17:15 +02:00
return ErrorLogger : : ErrorMessage : : FileLocation ( tok , this ) . stringify ( ) ;
2012-05-05 18:33:26 +02:00
}