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"
2017-05-27 04:33:47 +02:00
# include "errorlogger.h"
2012-05-05 18:33:26 +02:00
# include "mathlib.h"
# include "path.h"
# include "settings.h"
2017-05-27 04:33:47 +02:00
# include "token.h"
2017-05-18 22:25:49 +02:00
# include <simplecpp.h>
2012-05-05 18:33:26 +02:00
# include <cctype>
2017-05-27 04:33:47 +02:00
# include <cstring>
# include <set>
2012-05-05 18:33:26 +02:00
# 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 ) :
2017-08-09 20:00:26 +02:00
_front ( nullptr ) ,
_back ( nullptr ) ,
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 ) ;
2017-08-09 20:00:26 +02:00
_front = nullptr ;
_back = nullptr ;
2012-05-05 18:33:26 +02:00
_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
2017-05-06 11:57:02 +02:00
const bool isHex = MathLib : : isIntHex ( str ) ;
2017-05-05 14:47:58 +02:00
if ( isHex | | MathLib : : isOct ( str ) | | MathLib : : isBin ( str ) ) {
2017-03-04 08:47:53 +01:00
// TODO: It would be better if TokenList didn't simplify hexadecimal numbers
std : : string suffix ;
2017-05-05 14:47:58 +02:00
if ( isHex & &
2017-03-04 08:47:53 +01:00
str . size ( ) = = ( 2 + _settings - > int_bit / 4 ) & &
2017-05-05 14:47:58 +02:00
( str [ 2 ] > = ' 8 ' ) & & // includes A-F and a-f
2017-05-06 11:57:02 +02:00
MathLib : : getSuffix ( str ) . empty ( )
)
2017-03-04 08:47:53 +01:00
suffix = " U " ;
str = MathLib : : value ( str ) . str ( ) + suffix ;
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
2017-05-18 21:52:31 +02:00
simplecpp : : OutputList outputList ;
simplecpp : : TokenList tokens ( code , _files , file0 , & outputList ) ;
2015-12-27 14:57:22 +01:00
2017-05-18 21:52:31 +02:00
createTokens ( & tokens ) ;
2012-05-05 18:33:26 +02:00
2017-05-18 21:52:31 +02:00
return outputList . empty ( ) ;
2012-05-05 18:33:26 +02:00
}
2014-09-02 18:05:02 +02:00
//---------------------------------------------------------------------------
2017-05-17 15:38:31 +02:00
void TokenList : : createTokens ( const simplecpp : : TokenList * tokenList )
2017-05-17 14:57:54 +02:00
{
2017-05-17 15:38:31 +02:00
if ( tokenList - > cfront ( ) )
_files = tokenList - > cfront ( ) - > location . files ;
2017-05-17 14:57:54 +02:00
else
_files . clear ( ) ;
_isC = _isCPP = false ;
if ( ! _files . empty ( ) ) {
_isC = Path : : isC ( getSourceFilePath ( ) ) ;
_isCPP = Path : : isCPP ( getSourceFilePath ( ) ) ;
}
if ( _settings & & _settings - > enforcedLang ! = Settings : : None ) {
_isC = ( _settings - > enforcedLang = = Settings : : C ) ;
_isCPP = ( _settings - > enforcedLang = = Settings : : CPP ) ;
}
2017-05-17 15:38:31 +02:00
for ( const simplecpp : : Token * tok = tokenList - > cfront ( ) ; tok ; tok = tok - > next ) {
2017-05-18 21:52:31 +02:00
std : : string str = tok - > str ;
// Replace hexadecimal value with decimal
// TODO: Remove this
const bool isHex = MathLib : : isIntHex ( str ) ;
if ( isHex | | MathLib : : isOct ( str ) | | MathLib : : isBin ( str ) ) {
// TODO: It would be better if TokenList didn't simplify hexadecimal numbers
std : : string suffix ;
if ( isHex & &
2017-08-02 08:04:35 +02:00
_settings & &
2017-05-18 21:52:31 +02:00
str . size ( ) = = ( 2 + _settings - > int_bit / 4 ) & &
( str [ 2 ] > = ' 8 ' ) & & // includes A-F and a-f
MathLib : : getSuffix ( str ) . empty ( )
)
suffix = " U " ;
str = MathLib : : value ( str ) . str ( ) + suffix ;
}
// Float literal
if ( str . size ( ) > 1 & & str [ 0 ] = = ' . ' & & std : : isdigit ( str [ 1 ] ) )
str = ' 0 ' + str ;
2017-05-17 14:57:54 +02:00
if ( _back ) {
2017-05-18 21:52:31 +02:00
_back - > insertToken ( str ) ;
2017-05-17 14:57:54 +02:00
} else {
_front = new Token ( & _back ) ;
_back = _front ;
2017-05-18 21:52:31 +02:00
_back - > str ( str ) ;
2017-05-17 14:57:54 +02:00
}
if ( isCPP ( ) & & _back - > str ( ) = = " delete " )
_back - > isKeyword ( true ) ;
_back - > fileIndex ( tok - > location . fileIndex ) ;
_back - > linenr ( tok - > location . line ) ;
_back - > col ( tok - > location . col ) ;
_back - > isExpandedMacro ( ! tok - > macro . empty ( ) ) ;
}
if ( _settings & & _settings - > relativePaths ) {
for ( std : : size_t i = 0 ; i < _files . size ( ) ; i + + )
_files [ i ] = Path : : getRelativePath ( _files [ i ] , _settings - > basePaths ) ;
}
Token : : assignProgressValues ( _front ) ;
}
//---------------------------------------------------------------------------
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 ;
2017-06-08 15:32:35 +02:00
bool inCase ;
explicit AST_state ( bool cpp_ ) : depth ( 0 ) , inArrayAssignment ( 0 ) , cpp ( cpp_ ) , assign ( 0U ) , inCase ( false ) { }
2014-06-04 22:33:08 +02:00
} ;
2016-01-26 10:40:44 +01:00
static Token * skipDecl ( Token * tok )
{
if ( ! Token : : Match ( tok - > previous ( ) , " ( %name% " ) )
return tok ;
Token * vartok = tok ;
while ( Token : : Match ( vartok , " %name%|*|&|::|< " ) ) {
if ( vartok - > str ( ) = = " < " ) {
if ( vartok - > link ( ) )
vartok = vartok - > link ( ) ;
else
return tok ;
} else if ( Token : : Match ( vartok , " %name% [:=] " ) ) {
return vartok ;
}
vartok = vartok - > next ( ) ;
}
return tok ;
}
2013-11-11 16:39:34 +01:00
static bool iscast ( const Token * tok )
{
2016-01-25 10:29:24 +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 ;
2016-01-03 09:38:03 +01:00
if ( Token : : simpleMatch ( tok - > previous ( ) , " > " ) & & tok - > previous ( ) - > link ( ) )
return false ;
2016-01-03 09:37:38 +01:00
2014-05-04 18:36:04 +02:00
if ( Token : : Match ( tok , " ( (| typeof ( " ) & & Token : : Match ( tok - > link ( ) , " ) %num% " ) )
return true ;
2017-04-21 17:44:11 +02:00
if ( Token : : Match ( tok - > previous ( ) , " = ( %name% ) { " ) & & tok - > next ( ) - > varId ( ) = = 0 )
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 ( ) ;
2017-09-08 22:52:16 +02:00
if ( tok2 - > str ( ) = = " ) " ) {
return type | | tok2 - > strAt ( - 1 ) = = " * " | | Token : : simpleMatch ( 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 ( ) , " [[]);,?:.] " ) ) ;
2017-09-08 22:52:16 +02:00
}
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
2017-04-10 23:44:30 +02:00
if ( tok2 - > isStandardType ( ) & & ( tok2 - > next ( ) - > str ( ) ! = " ( " | | Token : : Match ( tok2 - > next ( ) , " ( * *| ) " ) ) )
2014-05-24 19:04:47 +02:00
type = true ;
2013-11-11 16:39:34 +01:00
}
return false ;
}
2017-05-24 20:18:31 +02:00
// int(1), int*(2), ..
static Token * findCppTypeInitPar ( Token * tok )
{
2017-05-24 20:24:56 +02:00
if ( ! tok | | ! Token : : Match ( tok - > previous ( ) , " [,()] %name% " ) )
2017-05-24 20:18:31 +02:00
return nullptr ;
2017-08-26 23:25:45 +02:00
bool istype = false ;
2017-05-24 20:18:31 +02:00
while ( Token : : Match ( tok , " %name%|::|< " ) ) {
if ( tok - > str ( ) = = " < " ) {
tok = tok - > link ( ) ;
if ( ! tok )
return nullptr ;
}
2017-08-26 23:25:45 +02:00
istype | = tok - > isStandardType ( ) ;
2017-05-24 20:18:31 +02:00
tok = tok - > next ( ) ;
}
2017-08-26 23:25:45 +02:00
if ( ! istype )
return nullptr ;
2017-05-24 20:18:31 +02:00
if ( ! Token : : Match ( tok , " [*&] " ) )
return nullptr ;
while ( Token : : Match ( tok , " [*&] " ) )
tok = tok - > next ( ) ;
return ( tok & & tok - > str ( ) = = " ( " ) ? tok : nullptr ;
}
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
{
2017-06-09 22:35:46 +02:00
const Token * nameToken = tok ;
while ( nameToken & & nameToken - > str ( ) = = " { " ) {
nameToken = nameToken - > previous ( ) ;
if ( nameToken & & nameToken - > str ( ) = = " , " & & Token : : simpleMatch ( nameToken - > previous ( ) , " } , " ) )
nameToken = nameToken - > linkAt ( - 1 ) ;
}
2015-10-18 16:58:15 +02:00
if ( ! nameToken )
return false ;
2017-06-09 22:35:46 +02:00
if ( nameToken - > str ( ) = = " > " & & nameToken - > link ( ) )
nameToken = nameToken - > link ( ) - > previous ( ) ;
2017-04-10 23:05:41 +02:00
2015-10-18 13:43:39 +02:00
const Token * endtok = nullptr ;
2017-06-09 22:35:46 +02:00
if ( Token : : Match ( nameToken , " %name% { !![ " ) )
2015-10-18 13:43:39 +02:00
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 ( ) ;
2017-04-21 21:02:46 +02:00
if ( state . inArrayAssignment & & Token : : Match ( tok - > previous ( ) , " [{,] . %name% " ) ) { // Jump over . in C style struct initialization
state . op . push ( tok ) ;
tok - > astOperand1 ( tok - > next ( ) ) ;
tok = tok - > tokAt ( 2 ) ;
}
2017-04-26 22:35:04 +02:00
if ( state . inArrayAssignment & & Token : : Match ( tok - > previous ( ) , " [{,] [ %num%|%name% ] " ) ) {
2017-04-10 07:25:18 +02:00
state . op . push ( tok ) ;
tok - > astOperand1 ( tok - > next ( ) ) ;
tok = tok - > tokAt ( 3 ) ;
}
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% " ) ) ;
2017-06-08 15:32:35 +02:00
} else if ( tok - > isName ( ) ) {
if ( Token : : Match ( tok , " return|case " ) ) {
if ( tok - > str ( ) = = " case " )
state . inCase = true ;
2014-06-26 09:03:02 +02:00
compileUnaryOp ( tok , state , compileExpression ) ;
state . op . pop ( ) ;
2017-06-08 15:32:35 +02:00
if ( state . inCase & & Token : : simpleMatch ( tok , " : ; " ) )
tok = tok - > next ( ) ;
2015-02-18 19:56:13 +01:00
} else if ( Token : : Match ( tok , " sizeof !!( " ) ) {
compileUnaryOp ( tok , state , compileExpression ) ;
state . op . pop ( ) ;
2017-05-24 20:18:31 +02:00
} else if ( state . cpp & & findCppTypeInitPar ( tok ) ) { // int(0), int*(123), ..
tok = findCppTypeInitPar ( tok ) ;
state . op . push ( tok ) ;
tok = tok - > tokAt ( 2 ) ;
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%|*|&|::|(|[ " ) ) {
2016-01-26 10:40:44 +01:00
tok = skipDecl ( tok ) ;
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 ( ) = = " { " ) {
2017-04-21 17:44:11 +02:00
const Token * prev = tok - > previous ( ) ;
2017-04-21 21:02:46 +02:00
if ( Token : : simpleMatch ( prev , " ) { " ) & & iscast ( prev - > link ( ) ) )
2017-04-21 17:44:11 +02:00
prev = prev - > link ( ) - > previous ( ) ;
2017-04-10 22:17:34 +02:00
if ( Token : : simpleMatch ( tok - > link ( ) , " } [ " ) ) {
tok = tok - > next ( ) ;
2017-06-09 22:35:46 +02:00
} else if ( state . cpp & & iscpp11init ( tok ) ) {
if ( state . op . empty ( ) | | Token : : Match ( tok - > previous ( ) , " [{,] " ) )
compileUnaryOp ( tok , state , compileExpression ) ;
else
compileBinOp ( tok , state , compileExpression ) ;
if ( Token : : simpleMatch ( tok , " } , " ) ) {
tok = tok - > next ( ) ;
}
2017-04-21 21:02:46 +02:00
} else if ( ! state . inArrayAssignment & & ! Token : : simpleMatch ( prev , " = " ) ) {
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 ) ;
2017-04-21 21:02:46 +02:00
while ( Token : : Match ( tok , " } [,};] " ) & & state . inArrayAssignment > 0U ) {
2015-07-21 11:40:42 +02:00
tok = tok - > next ( ) ;
state . inArrayAssignment - - ;
}
2014-07-31 23:14:44 +02:00
} else {
state . op . push ( tok ) ;
2017-04-09 22:06:13 +02:00
tok = tok - > tokAt ( 2 ) ;
2014-07-31 23:14:44 +02:00
}
}
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 ( ) = = " [ " ) {
2017-04-09 19:27:11 +02:00
if ( state . cpp & & isPrefixUnary ( tok , state . cpp ) & & Token : : Match ( tok - > link ( ) , " ] (|{ " ) ) { // 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)
2016-11-27 11:40:42 +01:00
// this must be consistent with isLambdaCaptureList
2017-04-09 17:49:55 +02:00
Token * const squareBracket = tok ;
if ( Token : : simpleMatch ( squareBracket - > link ( ) , " ] ( " ) ) {
Token * const roundBracket = squareBracket - > link ( ) - > next ( ) ;
Token * curlyBracket = roundBracket - > link ( ) - > next ( ) ;
2017-04-18 21:21:30 +02:00
while ( Token : : Match ( curlyBracket , " %name%|.|::|& " ) )
2017-04-09 17:49:55 +02:00
curlyBracket = curlyBracket - > next ( ) ;
if ( curlyBracket & & curlyBracket - > str ( ) = = " { " ) {
squareBracket - > astOperand1 ( roundBracket ) ;
roundBracket - > astOperand1 ( curlyBracket ) ;
state . op . push ( squareBracket ) ;
tok = curlyBracket - > link ( ) - > next ( ) ;
continue ;
}
} else {
Token * const curlyBracket = squareBracket - > link ( ) - > next ( ) ;
squareBracket - > astOperand1 ( curlyBracket ) ;
2015-10-20 23:55:29 +02:00
state . op . push ( squareBracket ) ;
tok = curlyBracket - > link ( ) - > next ( ) ;
2017-04-09 17:49:55 +02:00
continue ;
2015-10-20 23:55:29 +02:00
}
}
2017-04-09 17:49:55 +02:00
Token * tok2 = tok ;
if ( tok - > strAt ( 1 ) ! = " ] " )
compileBinOp ( tok , state , compileExpression ) ;
else
compileUnaryOp ( tok , state , compileExpression ) ;
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 ;
2017-06-08 15:32:35 +02:00
if ( ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) & & ( ! Token : : Match ( tok - > previous ( ) , " return|case " ) & & ( ! state . cpp | | ! Token : : Match ( tok - > previous ( ) , " throw|delete " ) ) ) )
2014-06-04 22:33:08 +02:00
| | ( 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 ) = = " : " ) {
2017-08-09 20:00:26 +02:00
state . op . push ( nullptr ) ;
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 ( ) = = " : " ) {
2017-06-08 15:32:35 +02:00
if ( state . depth = = 1U & & state . inCase )
break ;
2015-07-24 13:02:00 +02:00
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 ( ) = = " , " ) {
2017-04-22 11:23:11 +02:00
if ( Token : : simpleMatch ( tok , " , } " ) )
tok = tok - > next ( ) ;
else
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
}
2016-11-20 15:44:20 +01:00
static bool isLambdaCaptureList ( const Token * tok )
2016-11-20 15:14:49 +01:00
{
// a lambda expression '[x](y){}' is compiled as:
// [
2017-04-09 17:49:55 +02:00
// `-( <<-- optional
2016-11-20 15:14:49 +01:00
// `-{
// see compilePrecedence2
if ( tok - > str ( ) ! = " [ " )
return false ;
2017-04-10 23:29:15 +02:00
if ( ! Token : : Match ( tok - > link ( ) , " ] (|{ " ) )
return false ;
if ( Token : : simpleMatch ( tok - > astOperand1 ( ) , " { " ) & & tok - > astOperand1 ( ) = = tok - > link ( ) - > next ( ) )
2017-04-09 17:49:55 +02:00
return true ;
2016-11-20 15:14:49 +01:00
if ( ! tok - > astOperand1 ( ) | | tok - > astOperand1 ( ) - > str ( ) ! = " ( " )
return false ;
const Token * params = tok - > astOperand1 ( ) ;
if ( ! params | | ! params - > astOperand1 ( ) | | params - > astOperand1 ( ) - > str ( ) ! = " { " )
return false ;
return true ;
}
2017-03-19 07:26:11 +01:00
static Token * createAstAtToken ( Token * tok , bool cpp ) ;
// Compile inner expressions inside inner ({..}) and lambda bodies
static void createAstAtTokenInner ( Token * const tok1 , const Token * endToken , bool cpp )
{
for ( Token * tok = tok1 ; tok & & tok ! = endToken ; tok = tok ? tok - > next ( ) : nullptr ) {
2017-04-10 23:29:15 +02:00
if ( tok - > str ( ) = = " { " & & ! iscpp11init ( tok ) ) {
2017-04-21 21:02:46 +02:00
if ( Token : : simpleMatch ( tok - > astOperand1 ( ) , " , " ) )
continue ;
2017-03-19 07:26:11 +01:00
if ( Token : : simpleMatch ( tok - > previous ( ) , " ( { " ) )
;
2017-04-06 21:28:13 +02:00
// struct assignment
else if ( Token : : simpleMatch ( tok - > previous ( ) , " ) { " ) && Token::simpleMatch(tok->linkAt(-1), " ( struct " ) )
2017-04-27 20:53:27 +02:00
continue ;
2017-04-02 19:44:33 +02:00
// Lambda function
2017-03-19 07:26:11 +01:00
else if ( Token : : simpleMatch ( tok - > astParent ( ) , " ( " ) & &
Token : : simpleMatch ( tok - > astParent ( ) - > astParent ( ) , " [ " ) & &
tok - > astParent ( ) - > astParent ( ) - > astOperand1 ( ) & &
tok = = tok - > astParent ( ) - > astParent ( ) - > astOperand1 ( ) - > astOperand1 ( ) )
;
2017-04-05 11:00:02 +02:00
else {
// function argument is initializer list?
const Token * parent = tok - > astParent ( ) ;
while ( Token : : simpleMatch ( parent , " , " ) )
parent = parent - > astParent ( ) ;
if ( ! parent | | ! Token : : Match ( parent - > previous ( ) , " %name% ( " ) )
// not function argument..
continue ;
}
2017-03-19 07:26:11 +01:00
if ( Token : : simpleMatch ( tok - > previous ( ) , " ( { . " ) )
break ;
const Token * const endToken2 = tok - > link ( ) ;
for ( ; tok & & tok ! = endToken & & tok ! = endToken2 ; tok = tok ? tok - > next ( ) : nullptr )
tok = createAstAtToken ( tok , cpp ) ;
} else if ( tok - > str ( ) = = " [ " ) {
if ( isLambdaCaptureList ( tok ) ) {
2017-04-09 17:49:55 +02:00
tok = const_cast < Token * > ( tok - > astOperand1 ( ) ) ;
if ( tok - > str ( ) = = " ( " )
tok = const_cast < Token * > ( tok - > astOperand1 ( ) ) ;
2017-03-19 07:26:11 +01:00
const Token * const endToken2 = tok - > link ( ) ;
for ( ; tok & & tok ! = endToken & & tok ! = endToken2 ; tok = tok ? tok - > next ( ) : nullptr )
tok = createAstAtToken ( tok , cpp ) ;
}
}
}
}
2017-04-17 22:16:02 +02:00
static Token * findAstTop ( Token * tok1 , Token * tok2 )
{
2017-04-17 21:11:53 +02:00
for ( Token * tok = tok1 ; tok & & ( tok ! = tok2 ) ; tok = tok - > next ( ) ) {
if ( tok - > astParent ( ) | | tok - > astOperand1 ( ) | | tok - > astOperand2 ( ) )
return const_cast < Token * > ( tok - > astTop ( ) ) ;
if ( Token : : simpleMatch ( tok , " ( { " ) )
tok = tok - > link ( ) ;
}
for ( Token * tok = tok1 ; tok & & ( tok ! = tok2 ) ; tok = tok - > next ( ) ) {
if ( tok - > isName ( ) | | tok - > isNumber ( ) )
return tok ;
if ( Token : : simpleMatch ( tok , " ( { " ) )
tok = tok - > link ( ) ;
}
return nullptr ;
}
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 ( " ) ) {
2016-01-26 10:40:44 +01:00
Token * tok2 = skipDecl ( 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 ;
2017-04-17 21:11:53 +02:00
init1 = nullptr ;
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 ) ;
2017-03-19 07:26:11 +01:00
if ( Token : : simpleMatch ( tok2 , " ( { " ) ) {
state3 . op . push ( tok2 - > next ( ) ) ;
tok2 = tok2 - > link ( ) - > next ( ) ;
}
2014-06-04 22:33:08 +02:00
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 ( ) ) ) ;
2017-04-17 21:11:53 +02:00
tok2 = findAstTop ( semicolon1 - > next ( ) , semicolon2 ) ;
if ( tok2 )
semicolon2 - > astOperand1 ( tok2 ) ;
tok2 = findAstTop ( semicolon2 - > next ( ) , endPar ) ;
if ( tok2 )
semicolon2 - > astOperand2 ( tok2 ) ;
2017-03-19 07:26:11 +01:00
else if ( ! state3 . op . empty ( ) )
semicolon2 - > astOperand2 ( const_cast < Token * > ( state3 . op . top ( ) ) ) ;
2014-01-27 06:18:42 +01:00
semicolon1 - > astOperand2 ( semicolon2 ) ;
tok - > next ( ) - > astOperand1 ( tok ) ;
tok - > next ( ) - > astOperand2 ( semicolon1 ) ;
2017-03-19 07:26:11 +01:00
createAstAtTokenInner ( endPar - > link ( ) , endPar , cpp ) ;
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 ) ;
2017-06-08 15:32:35 +02:00
if ( Token : : Match ( tok , " return|case " ) | | ! tok - > previous ( ) | | Token : : Match ( tok , " %name% %op%|(|[|.|::|<|?|; " ) | | Token : : Match ( tok - > previous ( ) , " [;{}] %cop%|++|--|( !!{ " ) ) {
2016-09-10 14:54:43 +02:00
if ( cpp & & ( Token : : Match ( tok - > tokAt ( - 2 ) , " [;{}] new|delete %name% " ) | | Token : : Match ( tok - > tokAt ( - 3 ) , " [;{}] :: new|delete %name% " ) ) )
2015-10-20 23:55:29 +02:00
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
2017-03-19 07:26:11 +01:00
createAstAtTokenInner ( tok1 - > next ( ) , endToken , cpp ) ;
2014-01-27 06:18:42 +01:00
2017-07-31 17:58:07 +02:00
return endToken - > previous ( ) ;
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
}
2017-01-07 14:13:22 +01:00
void TokenList : : validateAst ( ) const
2015-12-12 15:39:38 +01:00
{
2016-02-02 08:55:26 +01:00
// Check for some known issues in AST to avoid crash/hang later on
std : : set < const Token * > safeAstTokens ; // list of "safe" AST tokens without endless recursion
2015-12-12 15:39:38 +01:00
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 ( ) )
2017-09-05 16:56:13 +02:00
throw InternalError ( tok , " Syntax Error: AST broken, binary operator has only one operand. " , InternalError : : AST ) ;
2015-12-12 15:39:38 +01:00
// Syntax error if we encounter "?" with operand2 that is not ":"
if ( tok - > astOperand2 ( ) & & tok - > str ( ) = = " ? " & & tok - > astOperand2 ( ) - > str ( ) ! = " : " )
2017-09-05 16:56:13 +02:00
throw InternalError ( tok , " Syntax Error: AST broken, ternary operator lacks ':'. " , InternalError : : AST ) ;
2015-12-12 15:39:38 +01:00
2016-02-02 08:55:26 +01:00
// Check for endless recursion
const Token * parent = tok - > astParent ( ) ;
if ( parent ) {
std : : set < const Token * > astTokens ; // list of anchestors
astTokens . insert ( tok ) ;
do {
if ( safeAstTokens . find ( parent ) ! = safeAstTokens . end ( ) )
break ;
if ( astTokens . find ( parent ) ! = astTokens . end ( ) )
2017-09-05 16:56:13 +02:00
throw InternalError ( tok , " AST broken: endless recursion from ' " + tok - > str ( ) + " ' " , InternalError : : AST ) ;
2016-02-02 08:55:26 +01:00
astTokens . insert ( parent ) ;
} while ( ( parent = parent - > astParent ( ) ) ! = nullptr ) ;
safeAstTokens . insert ( astTokens . begin ( ) , astTokens . end ( ) ) ;
} else
safeAstTokens . insert ( tok ) ;
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 ;
2016-01-31 22:16:58 +01:00
for ( const Token * t = _front ; t ; t = t - > next ( ) ) {
2015-12-27 17:38:15 +01:00
if ( tok = = t )
return true ;
}
return false ;
}
2017-10-03 22:10:13 +02:00
void TokenList : : simplifyStdType ( )
{
for ( Token * tok = front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " char|short|int|long|unsigned|signed|double|float " ) | | ( _settings - > standards . c > = Standards : : C99 & & Token : : Match ( tok , " complex|_Complex " ) ) ) {
bool isFloat = false ;
bool isSigned = false ;
bool isUnsigned = false ;
bool isComplex = false ;
unsigned int countLong = 0 ;
Token * typeSpec = nullptr ;
Token * tok2 = tok ;
for ( ; tok2 - > next ( ) ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " long " ) {
countLong + + ;
if ( ! isFloat )
typeSpec = tok2 ;
} else if ( tok2 - > str ( ) = = " short " ) {
typeSpec = tok2 ;
} else if ( tok2 - > str ( ) = = " unsigned " )
isUnsigned = true ;
else if ( tok2 - > str ( ) = = " signed " )
isSigned = true ;
else if ( Token : : Match ( tok2 , " float|double " ) ) {
isFloat = true ;
typeSpec = tok2 ;
} else if ( _settings - > standards . c > = Standards : : C99 & & Token : : Match ( tok2 , " complex|_Complex " ) )
isComplex = ! isFloat | | tok2 - > str ( ) = = " _Complex " | | Token : : Match ( tok2 - > next ( ) , " *|&|%name% " ) ; // Ensure that "complex" is not the variables name
else if ( Token : : Match ( tok2 , " char|int " ) ) {
if ( ! typeSpec )
typeSpec = tok2 ;
} else
break ;
}
if ( ! typeSpec ) { // unsigned i; or similar declaration
if ( ! isComplex ) { // Ensure that "complex" is not the variables name
tok - > str ( " int " ) ;
tok - > isSigned ( isSigned ) ;
tok - > isUnsigned ( isUnsigned ) ;
}
} else {
typeSpec - > isLong ( typeSpec - > isLong ( ) | | ( isFloat & & countLong = = 1 ) | | countLong > 1 ) ;
typeSpec - > isComplex ( typeSpec - > isComplex ( ) | | ( isFloat & & isComplex ) ) ;
typeSpec - > isSigned ( typeSpec - > isSigned ( ) | | isSigned ) ;
typeSpec - > isUnsigned ( typeSpec - > isUnsigned ( ) | | isUnsigned ) ;
// Remove specifiers
const Token * tok3 = tok - > previous ( ) ;
tok2 = tok2 - > previous ( ) ;
while ( tok3 ! = tok2 ) {
if ( tok2 ! = typeSpec & &
( isComplex | | ! Token : : Match ( tok2 , " complex|_Complex " ) ) ) // Ensure that "complex" is not the variables name
tok2 - > deleteThis ( ) ;
tok2 = tok2 - > previous ( ) ;
}
}
}
}
}