2012-05-05 18:33:26 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2016-01-01 14:34:45 +01:00
* Copyright ( C ) 2007 - 2016 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 ) ,
2014-06-24 18:45:06 +02:00
_settings ( settings ) ,
_isC ( false ) ,
_isCPP ( false )
2012-05-05 18:33:26 +02:00
{
}
TokenList : : ~ TokenList ( )
{
deallocateTokens ( ) ;
}
//---------------------------------------------------------------------------
2014-06-04 18:00:22 +02:00
const std : : string & TokenList : : getSourceFilePath ( ) const
{
if ( getFiles ( ) . empty ( ) ) {
2014-06-26 11:44:19 +02:00
return emptyString ;
2014-06-04 18:00:22 +02:00
}
return getFiles ( ) [ 0 ] ;
}
//---------------------------------------------------------------------------
2012-05-05 18:33:26 +02:00
// 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?
2014-07-07 21:25:30 +02:00
for ( std : : size_t i = 0 ; i < _files . size ( ) ; + + i )
2014-01-28 17:15:07 +01:00
if ( Path : : sameFileName ( _files [ i ] , fileName ) )
2014-07-08 21:47:22 +02:00
return ( unsigned int ) i ;
2014-01-28 17:15:07 +01:00
// The "_files" vector remembers what files have been tokenized..
2014-04-02 13:56:34 +02:00
_files . push_back ( Path : : simplifyPath ( fileName ) ) ;
2014-06-24 17:34:20 +02:00
// Update _isC and _isCPP properties
if ( _files . size ( ) = = 1 ) { // Update only useful if first file added to _files
if ( ! _settings ) {
_isC = Path : : isC ( getSourceFilePath ( ) ) ;
_isCPP = Path : : isCPP ( getSourceFilePath ( ) ) ;
} else {
_isC = _settings - > enforcedLang = = Settings : : C | | ( _settings - > enforcedLang = = Settings : : None & & Path : : isC ( getSourceFilePath ( ) ) ) ;
_isCPP = _settings - > enforcedLang = = Settings : : CPP | | ( _settings - > enforcedLang = = Settings : : None & & Path : : isCPP ( getSourceFilePath ( ) ) ) ;
}
}
2015-10-11 12:36:23 +02:00
return _files . size ( ) - 1U ;
2014-01-28 17:15:07 +01:00
}
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.
//---------------------------------------------------------------------------
2015-10-18 20:28:17 +02:00
void TokenList : : addtoken ( 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
2015-07-26 08:06:56 +02:00
if ( MathLib : : isIntHex ( str ) | | MathLib : : isOct ( str ) | | MathLib : : isBin ( str ) ) {
2014-03-09 17:54:49 +01:00
std : : ostringstream str2stream ;
2015-06-15 15:03:15 +02:00
str2stream < < MathLib : : toULongNumber ( str ) ;
2015-10-18 20:28:17 +02:00
str = str2stream . str ( ) ;
2014-03-09 17:54:49 +01:00
} else if ( str . compare ( 0 , 5 , " _Bool " ) = = 0 ) {
2015-10-18 20:28:17 +02:00
str = " bool " ;
2012-05-05 18:33:26 +02:00
}
if ( _back ) {
2015-10-18 20:28:17 +02:00
_back - > insertToken ( str ) ;
2012-05-05 18:33:26 +02:00
} else {
_front = new Token ( & _back ) ;
_back = _front ;
2015-10-18 20:28:17 +02:00
_back - > str ( str ) ;
2012-05-05 18:33:26 +02:00
}
2014-06-04 22:33:08 +02:00
if ( isCPP ( ) & & str = = " delete " )
_back - > isKeyword ( true ) ;
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 )
{
2015-05-27 21:39:31 +02:00
if ( tok = = nullptr )
2012-05-05 18:33:26 +02:00
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 ( ) ) ;
2014-06-26 10:57:39 +02:00
if ( ! tok - > originalName ( ) . empty ( ) )
_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 ( ) ) ;
2015-08-14 20:46:13 +02:00
dest - > tokType ( src - > tokType ( ) ) ;
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 )
{
2014-06-24 17:34:20 +02:00
appendFileIfNew ( file0 ) ;
2012-05-05 18:33:26 +02:00
// 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 ) ;
2015-12-24 08:16:58 +01:00
CurrentToken . clear ( ) ;
2014-01-03 18:53:37 +01:00
}
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 = = ' . ' & &
2014-05-31 18:02:19 +02:00
! CurrentToken . empty ( ) & &
2015-04-01 12:43:03 +02:00
std : : isdigit ( ( unsigned char ) CurrentToken [ 0 ] ) ) {
2012-05-05 18:33:26 +02:00
// 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 & &
2015-04-01 12:43:03 +02:00
std : : isdigit ( ( unsigned char ) CurrentToken [ 0 ] ) & &
2015-07-25 17:19:53 +02:00
( CurrentToken . back ( ) = = ' e ' | |
CurrentToken . back ( ) = = ' E ' ) & &
2015-07-26 08:06:56 +02:00
! MathLib : : isIntHex ( CurrentToken ) ) {
2012-05-05 18:33:26 +02:00
// Don't separate doubles "4.2e+10"
2015-04-01 12:43:03 +02:00
} else if ( CurrentToken . empty ( ) & & ch = = ' . ' & & std : : isdigit ( ( unsigned char ) code . peek ( ) ) ) {
2012-05-05 18:33:26 +02:00
// 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 ) ;
2015-06-25 08:57:09 +02:00
unsigned int row = 0 ;
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 ;
2015-12-24 08:16:58 +01:00
CurrentToken . clear ( ) ;
2014-01-03 18:53:37 +01:00
}
2012-05-05 18:33:26 +02:00
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 ) ;
2015-12-27 14:57:22 +01:00
// Split up ++ and --..
for ( Token * tok = _front ; tok ; tok = tok - > next ( ) ) {
if ( ! Token : : Match ( tok , " ++|-- " ) )
continue ;
if ( Token : : Match ( tok - > previous ( ) , " %num% ++|-- " ) | |
Token : : Match ( tok , " ++|-- %num% " ) ) {
tok - > str ( tok - > str ( ) [ 0 ] ) ;
tok - > insertToken ( tok - > str ( ) ) ;
}
}
2014-05-20 21:55:08 +02:00
Token : : assignProgressValues ( _front ) ;
2012-05-05 18:33:26 +02:00
2014-07-07 21:25:30 +02:00
for ( std : : size_t i = 1 ; i < _files . size ( ) ; i + + )
2012-05-05 18:33:26 +02:00
_files [ i ] = Path : : getRelativePath ( _files [ i ] , _settings - > _basePaths ) ;
return true ;
}
2014-09-02 18:05:02 +02:00
//---------------------------------------------------------------------------
unsigned long long TokenList : : calculateChecksum ( ) const
{
unsigned long long checksum = 0 ;
for ( const Token * tok = front ( ) ; tok ; tok = tok - > next ( ) ) {
2015-10-11 12:36:23 +02:00
const unsigned int subchecksum1 = tok - > flags ( ) + tok - > varId ( ) + tok - > tokType ( ) ;
2014-09-02 18:05:02 +02:00
unsigned int subchecksum2 = 0 ;
for ( std : : size_t i = 0 ; i < tok - > str ( ) . size ( ) ; i + + )
subchecksum2 + = ( unsigned int ) tok - > str ( ) [ i ] ;
if ( ! tok - > originalName ( ) . empty ( ) ) {
for ( std : : size_t i = 0 ; i < tok - > originalName ( ) . size ( ) ; i + + )
subchecksum2 + = ( unsigned int ) tok - > originalName ( ) [ i ] ;
}
checksum ^ = ( ( static_cast < unsigned long long > ( subchecksum1 ) < < 32 ) | subchecksum2 ) ;
2014-09-03 23:09:40 +02:00
2015-05-27 21:39:31 +02:00
const bool bit1 = ( checksum & 1 ) ! = 0 ;
2014-09-03 23:09:40 +02:00
checksum > > = 1 ;
if ( bit1 )
checksum | = ( 1ULL < < 63 ) ;
2014-09-02 18:05:02 +02:00
}
return checksum ;
}
2012-05-05 18:33:26 +02:00
//---------------------------------------------------------------------------
2014-06-04 22:33:08 +02:00
struct AST_state {
std : : stack < Token * > op ;
unsigned int depth ;
2014-07-31 23:14:44 +02:00
unsigned int inArrayAssignment ;
2014-06-04 22:33:08 +02:00
bool cpp ;
2015-07-24 13:02:00 +02:00
unsigned int assign ;
explicit AST_state ( bool cpp_ ) : depth ( 0 ) , inArrayAssignment ( 0 ) , cpp ( cpp_ ) , assign ( 0U ) { }
2014-06-04 22:33:08 +02:00
} ;
2013-11-11 16:39:34 +01:00
static bool iscast ( const Token * tok )
{
2015-01-31 10:50:39 +01:00
if ( ! Token : : Match ( tok , " ( %name% " ) )
2013-11-11 16:39:34 +01:00
return false ;
2014-09-12 06:43:52 +02:00
if ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) & & tok - > previous ( ) - > str ( ) ! = " return " )
2014-05-17 12:09:32 +02:00
return false ;
2014-05-04 18:36:04 +02:00
if ( Token : : Match ( tok , " ( (| typeof ( " ) & & Token : : Match ( tok - > link ( ) , " ) %num% " ) )
return true ;
2014-05-24 19:04:47 +02:00
bool type = false ;
2013-11-11 16:39:34 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2014-05-24 20:21:08 +02:00
while ( tok2 - > link ( ) & & Token : : Match ( tok2 , " (|[|< " ) )
2014-05-24 11:28:43 +02:00
tok2 = tok2 - > link ( ) - > next ( ) ;
2014-04-15 15:46:26 +02:00
if ( tok2 - > str ( ) = = " ) " )
2015-10-17 18:25:27 +02:00
return type | | tok2 - > strAt ( - 1 ) = = " * " | | Token : : Match ( tok2 , " ) &|~ " ) | |
2014-04-15 15:46:26 +02:00
( Token : : Match ( tok2 , " ) %any% " ) & &
2015-10-17 18:25:27 +02:00
! tok2 - > next ( ) - > isOp ( ) & &
! Token : : Match ( tok2 - > next ( ) , " [[]);,?:.] " ) ) ;
2015-01-31 10:50:39 +01:00
if ( ! Token : : Match ( tok2 , " %name%|*|&|:: " ) )
2014-04-15 15:46:26 +02:00
return false ;
2014-05-24 11:28:43 +02:00
2014-10-16 15:57:05 +02:00
if ( tok2 - > isStandardType ( ) & & tok2 - > next ( ) - > str ( ) ! = " ( " )
2014-05-24 19:04:47 +02:00
type = true ;
2013-11-11 16:39:34 +01:00
}
return false ;
}
2015-10-18 13:43:39 +02:00
// X{} X<Y>{} etc
2015-10-18 16:58:15 +02:00
static bool iscpp11init ( const Token * const tok )
2015-10-18 13:43:39 +02:00
{
2015-10-18 16:58:15 +02:00
const Token * nameToken = nullptr ;
if ( tok - > isName ( ) )
nameToken = tok ;
else if ( Token : : Match ( tok - > previous ( ) , " %name% { " ))
nameToken = tok - > previous ( ) ;
else if ( tok - > linkAt ( - 1 ) & & Token : : simpleMatch ( tok - > previous ( ) , " > { " ) && Token::Match(tok->linkAt(-1)->previous(), " % name % < " ))
nameToken = tok - > linkAt ( - 1 ) - > previous ( ) ;
if ( ! nameToken )
return false ;
2015-10-18 13:43:39 +02:00
const Token * endtok = nullptr ;
if ( Token : : Match ( nameToken , " %name% { " ) )
endtok = nameToken - > linkAt ( 1 ) ;
else if ( Token : : Match ( nameToken , " %name% < " ) & & Token : : simpleMatch ( nameToken - > linkAt ( 1 ) , " > { " ))
endtok = nameToken - > linkAt ( 1 ) - > linkAt ( 1 ) ;
else
return false ;
// There is no initialisation for example here: 'class Fred {};'
if ( ! Token : : simpleMatch ( endtok , " } ; " ) )
return true ;
const Token * prev = nameToken ;
while ( Token : : Match ( prev , " %name%|::|:|<|> " ) ) {
if ( Token : : Match ( prev , " class|struct " ) )
return false ;
2015-10-18 16:58:15 +02:00
2015-10-18 13:43:39 +02:00
prev = prev - > previous ( ) ;
}
return true ;
}
2014-06-04 22:33:08 +02:00
static void compileUnaryOp ( Token * & tok , AST_state & state , void ( * f ) ( Token * & tok , AST_state & state ) )
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 ( ) ;
2014-06-04 22:33:08 +02:00
state . depth + + ;
if ( tok & & state . depth < = AST_MAX_DEPTH )
f ( tok , state ) ;
state . depth - - ;
2014-05-17 12:09:32 +02:00
}
2013-11-04 11:26:16 +01:00
2014-06-04 22:33:08 +02:00
if ( ! state . op . empty ( ) ) {
unaryop - > astOperand1 ( state . op . top ( ) ) ;
state . op . pop ( ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
state . op . push ( unaryop ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
static void compileBinOp ( Token * & tok , AST_state & state , void ( * f ) ( Token * & tok , AST_state & state ) )
2013-11-04 11:26:16 +01:00
{
Token * binop = tok ;
2014-05-17 12:09:32 +02:00
if ( f ) {
tok = tok - > next ( ) ;
2014-06-04 22:33:08 +02:00
state . depth + + ;
if ( tok & & state . depth < = AST_MAX_DEPTH )
f ( tok , state ) ;
state . depth - - ;
2014-05-17 12:09:32 +02:00
}
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?
2014-06-04 22:33:08 +02:00
if ( ! state . op . empty ( ) ) {
binop - > astOperand2 ( state . op . top ( ) ) ;
state . op . pop ( ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
if ( ! state . op . empty ( ) ) {
binop - > astOperand1 ( state . op . top ( ) ) ;
state . op . pop ( ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
state . op . push ( binop ) ;
2013-11-04 11:26:16 +01:00
}
2013-03-02 15:49:48 +01:00
2014-06-04 22:33:08 +02:00
static void compileExpression ( Token * & tok , AST_state & state ) ;
2013-11-04 11:26:16 +01:00
2014-06-04 22:33:08 +02:00
static void compileTerm ( Token * & tok , AST_state & state )
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 ( ) ;
2014-09-14 11:35:04 +02:00
if ( state . inArrayAssignment & & tok - > str ( ) = = " . " & & Token : : Match ( tok - > previous ( ) , " ,|{ " ) ) // Jump over . in C style struct initialization
2014-07-31 23:14:44 +02:00
tok = tok - > next ( ) ;
2013-11-04 11:26:16 +01:00
if ( tok - > isLiteral ( ) ) {
2014-06-04 22:33:08 +02:00
state . op . push ( tok ) ;
2015-07-27 13:13:30 +02:00
do {
tok = tok - > next ( ) ;
} while ( Token : : Match ( tok , " %name%|%str% " ) ) ;
2014-06-26 09:03:02 +02:00
} else if ( tok - > isName ( ) & & tok - > str ( ) ! = " case " ) {
if ( tok - > str ( ) = = " return " ) {
compileUnaryOp ( tok , state , compileExpression ) ;
state . op . pop ( ) ;
2015-02-18 19:56:13 +01:00
} else if ( Token : : Match ( tok , " sizeof !!( " ) ) {
compileUnaryOp ( tok , state , compileExpression ) ;
state . op . pop ( ) ;
2015-10-18 13:43:39 +02:00
} else if ( state . cpp & & iscpp11init ( tok ) ) { // X{} X<Y>{} etc
2015-10-17 17:03:24 +02:00
state . op . push ( tok ) ;
tok = tok - > next ( ) ;
2015-10-18 13:43:39 +02:00
if ( tok - > str ( ) = = " < " )
tok = tok - > link ( ) - > next ( ) ;
2015-01-31 10:50:39 +01:00
} else if ( ! state . cpp | | ! Token : : Match ( tok , " new|delete %name%|*|&|::|(|[ " ) ) {
2014-06-26 09:03:02 +02:00
while ( tok - > next ( ) & & tok - > next ( ) - > isName ( ) )
tok = tok - > next ( ) ;
state . op . push ( tok ) ;
2015-07-27 13:13:30 +02:00
if ( Token : : Match ( tok , " %name% < " ) & & tok - > linkAt ( 1 ) )
2014-06-26 09:03:02 +02:00
tok = tok - > linkAt ( 1 ) ;
2013-11-04 11:26:16 +01:00
tok = tok - > next ( ) ;
2015-07-27 13:13:30 +02:00
if ( Token : : Match ( tok , " %str% " ) ) {
while ( Token : : Match ( tok , " %name%|%str% " ) )
tok = tok - > next ( ) ;
}
2014-06-26 09:03:02 +02:00
}
2014-02-05 06:05:48 +01:00
} else if ( tok - > str ( ) = = " { " ) {
2015-11-06 17:34:26 +01:00
if ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) ) {
compileBinOp ( tok , state , compileExpression ) ;
} else if ( ! state . inArrayAssignment & & tok - > strAt ( - 1 ) ! = " = " ) {
2014-07-31 23:14:44 +02:00
state . op . push ( tok ) ;
tok = tok - > link ( ) - > next ( ) ;
} else {
if ( tok - > link ( ) ! = tok - > next ( ) ) {
state . inArrayAssignment + + ;
compileUnaryOp ( tok , state , compileExpression ) ;
2015-07-21 11:40:42 +02:00
while ( Token : : Match ( tok , " } [,}] " ) & & state . inArrayAssignment > 0U ) {
tok = tok - > next ( ) ;
state . inArrayAssignment - - ;
}
2014-07-31 23:14:44 +02:00
} else {
state . op . push ( tok ) ;
}
}
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-06-04 22:33:08 +02:00
static void compileScope ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileTerm ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " :: " ) {
2014-06-04 18:08:51 +02:00
Token * binop = tok ;
tok = tok - > next ( ) ;
if ( tok & & tok - > str ( ) = = " ~ " ) // Jump over ~ of destructor definition
tok = tok - > next ( ) ;
if ( tok )
2014-06-04 22:33:08 +02:00
compileTerm ( tok , state ) ;
2014-06-04 18:08:51 +02:00
2014-09-29 10:59:58 +02:00
if ( binop - > previous ( ) & & ( binop - > previous ( ) - > isName ( ) | | ( binop - > previous ( ) - > link ( ) & & binop - > strAt ( - 1 ) = = " > " ) ) )
2014-06-04 22:33:08 +02:00
compileBinOp ( binop , state , nullptr ) ;
2014-02-25 06:36:10 +01:00
else
2014-06-04 22:33:08 +02:00
compileUnaryOp ( binop , state , nullptr ) ;
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-06-04 22:33:08 +02:00
static bool isPrefixUnary ( const Token * tok , bool cpp )
2013-11-25 20:58:40 +01:00
{
2014-05-17 12:09:32 +02:00
if ( ! tok - > previous ( )
2014-06-04 22:33:08 +02:00
| | ( ( Token : : Match ( tok - > previous ( ) , " (|[|{|%op%|;|}|?|:|,|.|return|:: " ) | | ( cpp & & tok - > strAt ( - 1 ) = = " throw " ) )
2015-08-14 20:46:13 +02:00
& & ( tok - > previous ( ) - > tokType ( ) ! = Token : : eIncDecOp | | tok - > tokType ( ) = = Token : : eIncDecOp ) ) )
2014-05-17 12:09:32 +02:00
return true ;
return tok - > strAt ( - 1 ) = = " ) " & & iscast ( tok - > linkAt ( - 1 ) ) ;
2014-05-08 06:48:53 +02:00
}
2014-06-04 22:33:08 +02:00
static void compilePrecedence2 ( Token * & tok , AST_state & state )
2014-05-08 06:48:53 +02:00
{
2014-06-04 22:33:08 +02:00
compileScope ( tok , state ) ;
2014-05-08 06:48:53 +02:00
while ( tok ) {
2015-08-14 20:46:13 +02:00
if ( tok - > tokType ( ) = = Token : : eIncDecOp & & ! isPrefixUnary ( tok , state . cpp ) ) {
2014-06-04 22:33:08 +02:00
compileUnaryOp ( tok , state , compileScope ) ;
2014-05-19 21:54:59 +02:00
} else if ( tok - > str ( ) = = " . " & & tok - > strAt ( 1 ) ! = " * " ) {
2014-06-04 18:08:51 +02:00
if ( tok - > strAt ( 1 ) = = " . " ) {
2014-06-04 22:33:08 +02:00
state . op . push ( tok ) ;
2014-06-04 18:08:51 +02:00
tok = tok - > tokAt ( 3 ) ;
break ;
} else
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileScope ) ;
2014-05-08 06:48:53 +02:00
} else if ( tok - > str ( ) = = " [ " ) {
2015-10-20 23:55:29 +02:00
bool lambda = false ;
2014-09-01 17:01:05 +02:00
if ( state . cpp & & isPrefixUnary ( tok , state . cpp ) & & tok - > link ( ) - > strAt ( 1 ) = = " ( " ) { // Lambda
2014-05-25 19:48:31 +02:00
// What we do here:
// - Nest the round bracket under the square bracket.
// - Nest what follows the lambda (if anything) with the lambda opening [
2015-06-17 19:32:44 +02:00
// - Compile the content of the lambda function as separate tree (this is done later)
2014-05-25 19:48:31 +02:00
Token * squareBracket = tok ;
Token * roundBracket = squareBracket - > link ( ) - > next ( ) ;
2015-10-20 23:55:29 +02:00
Token * curlyBracket = roundBracket - > link ( ) - > next ( ) ;
while ( Token : : Match ( curlyBracket , " %name%|.|:: " ) )
curlyBracket = curlyBracket - > next ( ) ;
if ( Token : : simpleMatch ( curlyBracket , " { " ) ) {
lambda = true ;
squareBracket - > astOperand1 ( roundBracket ) ;
roundBracket - > astOperand1 ( curlyBracket ) ;
state . op . push ( squareBracket ) ;
tok = curlyBracket - > link ( ) - > next ( ) ;
}
}
if ( ! lambda ) {
2014-05-25 19:48:31 +02:00
Token * tok2 = tok ;
2014-06-04 18:08:51 +02:00
if ( tok - > strAt ( 1 ) ! = " ] " )
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileExpression ) ;
2014-06-04 18:08:51 +02:00
else
2014-06-04 22:33:08 +02:00
compileUnaryOp ( tok , state , compileExpression ) ;
2014-05-25 19:48:31 +02:00
tok = tok2 - > link ( ) - > next ( ) ;
}
2014-05-17 12:09:32 +02:00
} 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 ( ) ;
2015-05-25 08:20:14 +02:00
const bool opPrevTopSquare = ! state . op . empty ( ) & & state . op . top ( ) & & state . op . top ( ) - > str ( ) = = " [ " ;
const std : : size_t oldOpSize = state . op . size ( ) ;
2014-06-04 22:33:08 +02:00
compileExpression ( tok , state ) ;
2014-05-17 12:09:32 +02:00
tok = tok2 ;
2014-06-04 22:33:08 +02:00
if ( ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) & & ( tok - > strAt ( - 1 ) ! = " return " & & ( ! state . cpp | | ! Token : : Match ( tok - > previous ( ) , " throw|delete " ) ) ) )
| | ( tok - > strAt ( - 1 ) = = " ] " & & ( ! state . cpp | | ! Token : : Match ( tok - > linkAt ( - 1 ) - > previous ( ) , " new|delete " ) ) )
2014-05-17 12:09:32 +02:00
| | ( tok - > strAt ( - 1 ) = = " > " & & tok - > linkAt ( - 1 ) )
2014-05-25 19:48:31 +02:00
| | ( tok - > strAt ( - 1 ) = = " ) " & & ! iscast ( tok - > linkAt ( - 1 ) ) ) // Don't treat brackets to clarify precedence as function calls
| | ( tok - > strAt ( - 1 ) = = " } " & & opPrevTopSquare ) ) {
2014-07-10 09:23:14 +02:00
const bool operandInside = oldOpSize < state . op . size ( ) ;
2014-06-04 18:08:51 +02:00
if ( operandInside )
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , nullptr ) ;
2014-05-17 12:09:32 +02:00
else
2014-06-04 22:33:08 +02:00
compileUnaryOp ( tok , state , nullptr ) ;
2014-05-17 12:09:32 +02:00
}
tok = tok - > link ( ) - > next ( ) ;
2015-10-18 16:58:15 +02:00
} else if ( state . cpp & & tok - > str ( ) = = " { " && iscpp11init(tok)) {
if ( Token : : simpleMatch ( tok , " { } " ) )
compileUnaryOp ( tok , state , compileExpression ) ;
else
compileBinOp ( tok , state , compileExpression ) ;
if ( Token : : simpleMatch ( tok , " } " ) )
tok = tok - > next ( ) ;
2013-11-25 20:58:40 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compilePrecedence3 ( Token * & tok , AST_state & state )
2014-05-17 12:09:32 +02:00
{
2014-06-04 22:33:08 +02:00
compilePrecedence2 ( tok , state ) ;
2014-05-17 12:09:32 +02:00
while ( tok ) {
2015-08-14 20:46:13 +02:00
if ( ( Token : : Match ( tok , " [+-!~*&] " ) | | tok - > tokType ( ) = = Token : : eIncDecOp ) & &
2014-06-04 22:33:08 +02:00
isPrefixUnary ( tok , state . cpp ) ) {
2014-06-04 18:08:51 +02:00
if ( Token : : Match ( tok , " * [*,)] " ) ) {
2015-08-16 14:22:46 +02:00
Token * tok2 = tok - > next ( ) ;
2014-06-04 18:08:51 +02:00
while ( tok2 - > next ( ) & & tok2 - > str ( ) = = " * " )
tok2 = tok2 - > next ( ) ;
if ( Token : : Match ( tok2 , " [>),] " ) ) {
tok = tok2 ;
continue ;
}
}
2014-06-04 22:33:08 +02:00
compileUnaryOp ( tok , state , compilePrecedence3 ) ;
2014-05-17 12:09:32 +02:00
} else if ( tok - > str ( ) = = " ( " & & iscast ( tok ) ) {
Token * tok2 = tok ;
tok = tok - > link ( ) - > next ( ) ;
2014-06-04 22:33:08 +02:00
compilePrecedence3 ( tok , state ) ;
compileUnaryOp ( tok2 , state , nullptr ) ;
2015-01-31 10:50:39 +01:00
} else if ( state . cpp & & Token : : Match ( tok , " new %name%|::|( " ) ) {
2014-10-11 08:32:49 +02:00
Token * newtok = tok ;
2014-06-04 18:08:51 +02:00
tok = tok - > next ( ) ;
2014-10-12 12:13:01 +02:00
bool innertype = false ;
2014-10-11 11:27:13 +02:00
if ( tok - > str ( ) = = " ( " ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " ( &| %name% " ) & & Token : : Match ( tok - > link ( ) , " ) ( %type% " ) & & Token : : simpleMatch ( tok - > link ( ) - > linkAt ( 1 ) , " ) ( " ) )
2014-10-11 11:27:13 +02:00
tok = tok - > link ( ) - > next ( ) ;
2014-10-12 11:12:25 +02:00
if ( Token : : Match ( tok - > link ( ) , " ) ::| %type% " ) )
2014-10-11 11:27:13 +02:00
tok = tok - > link ( ) - > next ( ) ;
2014-10-12 12:57:01 +02:00
else if ( Token : : Match ( tok , " ( %type% " ) & & Token : : Match ( tok - > link ( ) , " ) [() ; , [ ] " )) {
2014-10-11 11:27:13 +02:00
tok = tok - > next ( ) ;
2014-10-12 12:13:01 +02:00
innertype = true ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok , " ( &| %name% " ) & & Token : : simpleMatch ( tok - > link ( ) , " ) ( " ) ) {
2014-10-11 13:20:48 +02:00
tok = tok - > next ( ) ;
2014-10-12 12:13:01 +02:00
innertype = true ;
2014-10-13 19:12:20 +02:00
} else {
/* bad code */
continue ;
2014-10-12 12:13:01 +02:00
}
2014-10-11 11:27:13 +02:00
}
2014-06-04 22:33:08 +02:00
state . op . push ( tok ) ;
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( tok , " %name%|*|&|<|:: " ) ) {
2014-06-04 18:08:51 +02:00
if ( tok - > link ( ) )
tok = tok - > link ( ) ;
tok = tok - > next ( ) ;
}
2014-10-10 19:05:31 +02:00
if ( Token : : Match ( tok , " ( const| %type% ) ( " ) ) {
2014-10-10 12:47:01 +02:00
state . op . push ( tok - > next ( ) ) ;
2014-10-10 19:05:31 +02:00
tok = tok - > link ( ) - > next ( ) ;
2014-10-10 12:47:01 +02:00
compileBinOp ( tok , state , compilePrecedence2 ) ;
2015-11-06 17:34:26 +01:00
} else if ( tok & & ( tok - > str ( ) = = " [ " | | tok - > str ( ) = = " ( " | | tok - > str ( ) = = " { " ))
2014-09-29 10:26:15 +02:00
compilePrecedence2 ( tok , state ) ;
2014-10-12 12:57:01 +02:00
else if ( innertype & & Token : : simpleMatch ( tok , " ) [ " )) {
tok = tok - > next ( ) ;
compilePrecedence2 ( tok , state ) ;
}
2014-10-11 08:32:49 +02:00
compileUnaryOp ( newtok , state , nullptr ) ;
2014-10-12 12:13:01 +02:00
if ( innertype & & Token : : simpleMatch ( tok , " ) , " ) )
2014-10-12 10:20:03 +02:00
tok = tok - > next ( ) ;
2015-01-31 10:50:39 +01:00
} else if ( state . cpp & & Token : : Match ( tok , " delete %name%|*|&|::|(|[ " ) ) {
2014-06-04 18:08:51 +02:00
Token * tok2 = tok ;
tok = tok - > next ( ) ;
2015-05-27 21:39:31 +02:00
if ( tok & & tok - > str ( ) = = " [ " )
2014-06-04 18:08:51 +02:00
tok = tok - > link ( ) - > next ( ) ;
2014-06-04 22:33:08 +02:00
compilePrecedence3 ( tok , state ) ;
compileUnaryOp ( tok2 , state , nullptr ) ;
2014-05-17 12:09:32 +02:00
}
2014-06-04 18:08:51 +02:00
// TODO: Handle sizeof
2014-05-17 12:09:32 +02:00
else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compilePointerToElem ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compilePrecedence3 ( tok , state ) ;
2014-05-19 21:54:59 +02:00
while ( tok ) {
if ( Token : : simpleMatch ( tok , " . * " ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compilePrecedence3 ) ;
2014-05-19 21:54:59 +02:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileMulDiv ( Token * & tok , AST_state & state )
2014-05-19 21:54:59 +02:00
{
2014-06-04 22:33:08 +02:00
compilePointerToElem ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2014-05-24 19:04:47 +02:00
if ( Token : : Match ( tok , " [/%] " ) | | ( tok - > str ( ) = = " * " & & ! tok - > astOperand1 ( ) ) ) {
2014-04-26 13:32:08 +02:00
if ( Token : : Match ( tok , " * [*,)] " ) ) {
2015-08-16 14:22:46 +02:00
Token * tok2 = tok - > next ( ) ;
2014-05-17 12:09:32 +02:00
while ( tok2 - > next ( ) & & tok2 - > str ( ) = = " * " )
tok2 = tok2 - > next ( ) ;
2014-06-04 18:08:51 +02:00
if ( Token : : Match ( tok2 , " [>),] " ) ) {
tok = tok2 ;
2014-05-17 12:09:32 +02:00
break ;
}
2014-04-26 13:32:08 +02:00
}
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compilePointerToElem ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileAddSub ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileMulDiv ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2014-05-24 19:04:47 +02:00
if ( Token : : Match ( tok , " +|- " ) & & ! tok - > astOperand1 ( ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileMulDiv ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileShift ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileAddSub ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " <<|>> " ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileAddSub ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileRelComp ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileShift ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2014-06-04 18:08:51 +02:00
if ( Token : : Match ( tok , " <|<=|>=|> " ) & & ! tok - > link ( ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileShift ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2012-12-16 10:06:55 +01:00
2014-06-04 22:33:08 +02:00
static void compileEqComp ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileRelComp ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " ==|!= " ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileRelComp ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileAnd ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileEqComp ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2014-05-24 19:04:47 +02:00
if ( tok - > str ( ) = = " & " & & ! tok - > astOperand1 ( ) ) {
2014-06-04 18:08:51 +02:00
Token * tok2 = tok - > next ( ) ;
2014-09-28 22:05:05 +02:00
if ( ! tok2 )
break ;
2014-06-04 18:08:51 +02:00
if ( tok2 - > str ( ) = = " & " )
tok2 = tok2 - > next ( ) ;
2014-09-14 11:26:16 +02:00
if ( state . cpp & & Token : : Match ( tok2 , " ,|) " ) ) {
2014-06-04 18:08:51 +02:00
tok = tok2 ;
break ; // rValue reference
}
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileEqComp ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileXor ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileAnd ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " ^ " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileAnd ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileOr ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileXor ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " | " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileXor ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileLogicAnd ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileOr ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " && " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileOr ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileLogicOr ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileLogicAnd ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " || " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileLogicAnd ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileAssignTernary ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileLogicOr ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2015-07-24 13:02:00 +02:00
if ( tok - > isAssignmentOp ( ) ) {
state . assign + + ;
compileBinOp ( tok , state , compileAssignTernary ) ;
if ( state . assign > 0U )
state . assign - - ;
} else if ( tok - > str ( ) = = " ? " ) {
2015-10-12 18:14:56 +02:00
// http://en.cppreference.com/w/cpp/language/operator_precedence says about ternary operator:
// "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
2015-12-25 09:51:08 +01:00
// Hence, we rely on Tokenizer::prepareTernaryOpForAST() to add such parentheses where necessary.
2015-07-24 13:02:00 +02:00
if ( tok - > strAt ( 1 ) = = " : " ) {
2014-06-04 22:33:08 +02:00
state . op . push ( 0 ) ;
2014-05-19 21:54:59 +02:00
}
2015-07-24 13:02:00 +02:00
const unsigned int assign = state . assign ;
state . assign = 0U ;
compileBinOp ( tok , state , compileAssignTernary ) ;
state . assign = assign ;
} else if ( tok - > str ( ) = = " : " ) {
if ( state . assign > 0U )
break ;
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileAssignTernary ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileComma ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileAssignTernary ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " , " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileAssignTernary ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileExpression ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
if ( state . 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-06-04 22:33:08 +02:00
compileComma ( tok , state ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
static Token * createAstAtToken ( Token * tok , bool cpp )
2014-01-27 06:18:42 +01:00
{
2015-10-12 18:14:56 +02:00
if ( Token : : simpleMatch ( tok , " for ( " ) ) {
2014-01-27 06:18:42 +01:00
Token * tok2 = tok - > tokAt ( 2 ) ;
2014-02-16 11:47:52 +01:00
Token * init1 = nullptr ;
2015-10-18 11:42:18 +02:00
Token * const endPar = tok - > next ( ) - > link ( ) ;
2014-01-27 06:18:42 +01:00
while ( tok2 & & tok2 ! = endPar & & tok2 - > str ( ) ! = " ; " ) {
if ( tok2 - > str ( ) = = " < " & & tok2 - > link ( ) ) {
tok2 = tok2 - > link ( ) ;
if ( ! tok2 )
break ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok2 , " %name% %op%|(|[|.|:|:: " ) | | Token : : Match ( tok2 - > previous ( ) , " [( ; { } ] % cop % | ( " )) {
2014-01-27 06:18:42 +01:00
init1 = tok2 ;
2014-06-04 22:33:08 +02:00
AST_state state1 ( cpp ) ;
compileExpression ( tok2 , state1 ) ;
2014-09-14 11:26:16 +02:00
if ( Token : : Match ( tok2 , " ;|) " ) )
2014-01-27 06:18:42 +01:00
break ;
init1 = 0 ;
2014-01-15 17:32:14 +01:00
}
2015-11-08 15:09:39 +01:00
if ( ! tok2 ) // #7109 invalid code
return nullptr ;
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 ( ) ;
2014-06-04 22:33:08 +02:00
AST_state state2 ( cpp ) ;
compileExpression ( tok2 , state2 ) ;
2014-01-27 06:18:42 +01:00
Token * const semicolon2 = tok2 ;
2015-12-26 23:51:10 +01:00
if ( ! semicolon2 )
return nullptr ; // invalid code #7235
2014-01-27 06:18:42 +01:00
tok2 = tok2 - > next ( ) ;
2014-06-04 22:33:08 +02:00
AST_state state3 ( cpp ) ;
compileExpression ( tok2 , state3 ) ;
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 ( ) ) ) ;
2015-10-18 11:42:18 +02:00
tok2 = endPar ;
2014-01-27 06:18:42 +01:00
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 ) ;
2015-10-18 11:42:18 +02:00
return endPar ;
2014-01-27 06:18:42 +01:00
}
2014-01-28 06:11:53 +01:00
if ( Token : : simpleMatch ( tok , " ( { " ) )
return tok ;
2015-10-18 13:43:39 +02:00
if ( Token : : Match ( tok , " %type% < " ) & & ! Token : : Match ( tok - > linkAt ( 1 ) , " > [({] " ) )
2014-02-17 17:37:39 +01:00
return tok - > linkAt ( 1 ) ;
2015-11-18 21:37:37 +01:00
if ( tok - > str ( ) = = " return " | | ! tok - > previous ( ) | | Token : : Match ( tok , " %name% %op%|(|[|.|::|<|?|; " ) | | Token : : Match ( tok - > previous ( ) , " [;{}] %cop%|++|--|( !!{ " ) ) {
2015-10-20 23:55:29 +02:00
if ( cpp & & Token : : Match ( tok - > tokAt ( - 2 ) , " [;{}] new|delete %name% " ) )
tok = tok - > previous ( ) ;
2014-01-27 06:18:42 +01:00
Token * const tok1 = tok ;
2014-06-04 22:33:08 +02:00
AST_state state ( cpp ) ;
compileExpression ( tok , state ) ;
2014-01-27 06:18:42 +01:00
Token * const endToken = tok ;
2015-10-18 11:42:18 +02:00
if ( endToken = = tok1 | | ! endToken )
2014-01-28 06:11:53 +01:00
return tok1 ;
2014-01-27 06:18:42 +01:00
2015-06-17 19:32:44 +02:00
// Compile inner expressions inside inner ({..}) and lambda bodies
2015-11-08 15:09:39 +01:00
for ( tok = tok1 - > next ( ) ; tok & & tok ! = endToken ; tok = tok ? tok - > next ( ) : nullptr ) {
2015-06-17 19:32:44 +02:00
if ( tok - > str ( ) ! = " { " )
2014-01-27 06:18:42 +01:00
continue ;
2015-06-17 19:32:44 +02:00
if ( Token : : simpleMatch ( tok - > previous ( ) , " ( { " ) )
;
else if ( Token : : simpleMatch ( tok - > astParent ( ) , " ( " ) & &
Token : : simpleMatch ( tok - > astParent ( ) - > astParent ( ) , " [ " ) & &
2015-06-25 08:57:09 +02:00
tok - > astParent ( ) - > astParent ( ) - > astOperand1 ( ) & &
2015-06-17 19:32:44 +02:00
tok = = tok - > astParent ( ) - > astParent ( ) - > astOperand1 ( ) - > astOperand1 ( ) )
;
else
continue ;
if ( Token : : simpleMatch ( tok - > previous ( ) , " ( { . " ) )
2014-08-25 19:10:16 +02:00
break ;
2015-06-17 19:32:44 +02:00
const Token * const endToken2 = tok - > link ( ) ;
2015-11-08 15:09:39 +01:00
for ( ; tok & & tok ! = endToken & & tok ! = endToken2 ; tok = tok ? tok - > next ( ) : nullptr )
2014-06-04 22:33:08 +02:00
tok = createAstAtToken ( tok , cpp ) ;
2012-12-15 20:21:09 +01:00
}
2014-01-27 06:18:42 +01:00
2015-11-08 15:09:39 +01:00
return endToken ? endToken - > previous ( ) : nullptr ;
2014-01-27 06:18:42 +01:00
}
return tok ;
}
2015-01-20 11:22:22 +01:00
void TokenList : : createAst ( )
2014-01-27 06:18:42 +01:00
{
2015-12-12 20:01:03 +01:00
for ( Token * tok = _front ; tok ; tok = tok ? tok - > next ( ) : nullptr ) {
2014-06-04 22:33:08 +02:00
tok = createAstAtToken ( tok , isCPP ( ) ) ;
2012-12-15 20:21:09 +01:00
}
2015-12-12 15:39:38 +01:00
}
void TokenList : : validateAst ( )
{
2015-12-19 20:36:30 +01:00
std : : set < const Token * > astTokens ;
2015-12-12 15:39:38 +01:00
// Verify that ast looks ok
for ( const Token * tok = _front ; tok ; tok = tok - > next ( ) ) {
// Syntax error if binary operator only has 1 operand
if ( ( tok - > isAssignmentOp ( ) | | tok - > isComparisonOp ( ) | | Token : : Match ( tok , " [|^/%] " ) ) & & tok - > astOperand1 ( ) & & ! tok - > astOperand2 ( ) )
throw InternalError ( tok , " Syntax Error: AST broken, binary operator has only one operand. " , InternalError : : SYNTAX ) ;
// Syntax error if we encounter "?" with operand2 that is not ":"
if ( tok - > astOperand2 ( ) & & tok - > str ( ) = = " ? " & & tok - > astOperand2 ( ) - > str ( ) ! = " : " )
throw InternalError ( tok , " Syntax Error: AST broken, ternary operator lacks ':'. " , InternalError : : SYNTAX ) ;
// check for endless recursion
const Token * parent = tok ;
2015-12-15 09:34:04 +01:00
while ( ( parent = parent - > astParent ( ) ) ! = nullptr ) {
2015-12-12 15:39:38 +01:00
if ( parent = = tok )
throw InternalError ( tok , " AST broken: endless recursion from ' " + tok - > str ( ) + " ' " , InternalError : : SYNTAX ) ;
2015-12-19 20:36:30 +01:00
if ( astTokens . find ( parent ) ! = astTokens . end ( ) ) {
break ;
2015-12-23 10:26:12 +01:00
}
2015-12-19 20:36:30 +01:00
astTokens . insert ( parent ) ;
2015-12-12 15:39:38 +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
}
2015-12-27 17:38:15 +01:00
bool TokenList : : validateToken ( const Token * tok ) const
{
if ( ! tok )
return true ;
for ( Token * t = _front ; t ; t = t - > next ( ) ) {
if ( tok = = t )
return true ;
}
return false ;
}