2016-07-20 12:21:00 +02:00
/*
* simplecpp - A simple and high - fidelity C / C + + preprocessor library
2022-03-22 21:14:48 +01:00
* Copyright ( C ) 2016 - 2022 Daniel Marjamäki .
2016-07-20 12:21:00 +02:00
*
* This library is free software : you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation , either
* version 3 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see < http : //www.gnu.org/licenses/>.
*/
2017-06-21 12:09:50 +02:00
# if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
2018-01-13 18:08:23 +01:00
# define SIMPLECPP_WINDOWS
2017-06-21 12:09:50 +02:00
# define NOMINMAX
# endif
2023-09-13 10:30:42 +02:00
2016-07-20 12:21:00 +02:00
# include "simplecpp.h"
# include <algorithm>
2023-04-05 21:17:48 +02:00
# include <cassert>
2023-09-13 10:30:42 +02:00
# include <cctype>
2021-04-30 17:41:59 +02:00
# include <climits>
2022-12-09 07:18:13 +01:00
# include <cstddef>
2023-09-13 10:30:42 +02:00
# include <cstdio>
2022-12-09 07:18:13 +01:00
# include <cstdlib>
2016-07-20 12:21:00 +02:00
# include <cstring>
2022-03-22 21:14:48 +01:00
# include <ctime>
2017-05-28 15:23:15 +02:00
# include <exception>
2022-12-09 07:18:13 +01:00
# include <fstream> // IWYU pragma: keep
2016-07-20 12:21:00 +02:00
# include <iostream>
2017-05-28 15:23:15 +02:00
# include <limits>
2023-09-13 10:30:42 +02:00
# include <list>
# include <map>
# include <set>
2022-12-09 07:18:13 +01:00
# include <sstream> // IWYU pragma: keep
2016-07-20 12:21:00 +02:00
# include <stack>
2017-05-28 15:23:15 +02:00
# include <stdexcept>
2023-09-13 10:30:42 +02:00
# include <string>
2022-03-22 21:14:48 +01:00
# if __cplusplus >= 201103L
2023-09-13 10:30:42 +02:00
# ifdef SIMPLECPP_WINDOWS
# include <mutex>
# endif
2022-03-22 21:14:48 +01:00
# include <unordered_map>
# endif
2017-05-28 15:23:15 +02:00
# include <utility>
2023-09-13 10:30:42 +02:00
# include <vector>
2016-07-20 12:21:00 +02:00
2018-01-13 18:08:23 +01:00
# ifdef SIMPLECPP_WINDOWS
2016-08-21 17:08:40 +02:00
# include <windows.h>
# undef ERROR
# endif
2023-09-13 10:30:42 +02:00
# if __cplusplus >= 201103L
# define OVERRIDE override
# define EXPLICIT explicit
# else
# define OVERRIDE
# define EXPLICIT
# endif
2022-03-22 21:14:48 +01:00
# if (__cplusplus < 201103L) && !defined(__APPLE__)
# define nullptr NULL
# endif
2017-05-26 16:45:07 +02:00
static bool isHex ( const std : : string & s )
{
2017-05-18 21:40:47 +02:00
return s . size ( ) > 2 & & ( s . compare ( 0 , 2 , " 0x " ) = = 0 | | s . compare ( 0 , 2 , " 0X " ) = = 0 ) ;
}
2019-09-25 20:19:26 +02:00
static bool isOct ( const std : : string & s )
{
return s . size ( ) > 1 & & ( s [ 0 ] = = ' 0 ' ) & & ( s [ 1 ] > = ' 0 ' ) & & ( s [ 1 ] < ' 8 ' ) ;
}
2023-11-03 13:55:54 +01:00
// TODO: added an undercore since this conflicts with a function of the same name in utils.h from Cppcheck source when building Cppcheck with MSBuild
2022-03-22 21:14:48 +01:00
static bool isStringLiteral_ ( const std : : string & s )
{
return s . size ( ) > 1 & & ( s [ 0 ] = = ' \" ' ) & & ( * s . rbegin ( ) = = ' \" ' ) ;
}
2023-11-03 13:55:54 +01:00
// TODO: added an undercore since this conflicts with a function of the same name in utils.h from Cppcheck source when building Cppcheck with MSBuild
2022-03-22 21:14:48 +01:00
static bool isCharLiteral_ ( const std : : string & s )
{
// char literal patterns can include 'a', '\t', '\000', '\xff', 'abcd', and maybe ''
// This only checks for the surrounding '' but doesn't parse the content.
return s . size ( ) > 1 & & ( s [ 0 ] = = ' \' ' ) & & ( * s . rbegin ( ) = = ' \' ' ) ;
}
2016-07-20 12:21:00 +02:00
2017-05-26 16:45:07 +02:00
static const simplecpp : : TokenString DEFINE ( " define " ) ;
static const simplecpp : : TokenString UNDEF ( " undef " ) ;
2016-07-20 12:21:00 +02:00
2017-05-26 16:45:07 +02:00
static const simplecpp : : TokenString INCLUDE ( " include " ) ;
2016-07-20 12:21:00 +02:00
2017-05-26 16:45:07 +02:00
static const simplecpp : : TokenString ERROR ( " error " ) ;
static const simplecpp : : TokenString WARNING ( " warning " ) ;
2016-07-20 12:21:00 +02:00
2017-05-26 16:45:07 +02:00
static const simplecpp : : TokenString IF ( " if " ) ;
static const simplecpp : : TokenString IFDEF ( " ifdef " ) ;
static const simplecpp : : TokenString IFNDEF ( " ifndef " ) ;
static const simplecpp : : TokenString DEFINED ( " defined " ) ;
static const simplecpp : : TokenString ELSE ( " else " ) ;
static const simplecpp : : TokenString ELIF ( " elif " ) ;
static const simplecpp : : TokenString ENDIF ( " endif " ) ;
2016-07-21 12:47:00 +02:00
2017-05-26 16:45:07 +02:00
static const simplecpp : : TokenString PRAGMA ( " pragma " ) ;
static const simplecpp : : TokenString ONCE ( " once " ) ;
2016-07-20 20:03:27 +02:00
2021-04-26 16:25:39 +02:00
static const simplecpp : : TokenString HAS_INCLUDE ( " __has_include " ) ;
2023-10-05 18:20:42 +02:00
static const simplecpp : : TokenString INNER_COMMA ( " ,, " ) ;
2017-05-26 16:45:07 +02:00
template < class T > static std : : string toString ( T t )
{
2022-09-30 07:26:48 +02:00
// NOLINTNEXTLINE(misc-const-correctness) - false positive
2017-05-26 16:45:07 +02:00
std : : ostringstream ostr ;
ostr < < t ;
return ostr . str ( ) ;
}
2016-07-21 15:59:59 +02:00
2017-05-26 16:45:07 +02:00
static long long stringToLL ( const std : : string & s )
{
long long ret ;
const bool hex = isHex ( s ) ;
2019-09-25 20:19:26 +02:00
const bool oct = isOct ( s ) ;
std : : istringstream istr ( hex ? s . substr ( 2 ) : oct ? s . substr ( 1 ) : s ) ;
2017-05-26 16:45:07 +02:00
if ( hex )
istr > > std : : hex ;
2019-09-25 20:19:26 +02:00
else if ( oct )
istr > > std : : oct ;
2017-05-26 16:45:07 +02:00
istr > > ret ;
return ret ;
}
2016-07-21 15:59:59 +02:00
2017-05-26 16:45:07 +02:00
static unsigned long long stringToULL ( const std : : string & s )
{
unsigned long long ret ;
const bool hex = isHex ( s ) ;
2019-09-25 20:19:26 +02:00
const bool oct = isOct ( s ) ;
std : : istringstream istr ( hex ? s . substr ( 2 ) : oct ? s . substr ( 1 ) : s ) ;
2017-05-26 16:45:07 +02:00
if ( hex )
istr > > std : : hex ;
2019-09-25 20:19:26 +02:00
else if ( oct )
istr > > std : : oct ;
2017-05-26 16:45:07 +02:00
istr > > ret ;
return ret ;
}
2016-08-06 11:38:20 +02:00
2017-05-26 16:45:07 +02:00
static bool endsWith ( const std : : string & s , const std : : string & e )
{
2022-12-09 07:18:13 +01:00
return ( s . size ( ) > = e . size ( ) ) & & std : : equal ( e . rbegin ( ) , e . rend ( ) , s . rbegin ( ) ) ;
2017-05-26 16:45:07 +02:00
}
2016-07-31 20:48:55 +02:00
2017-05-26 16:45:07 +02:00
static bool sameline ( const simplecpp : : Token * tok1 , const simplecpp : : Token * tok2 )
{
return tok1 & & tok2 & & tok1 - > location . sameline ( tok2 - > location ) ;
}
2016-07-31 20:48:55 +02:00
2017-05-26 16:45:07 +02:00
static bool isAlternativeBinaryOp ( const simplecpp : : Token * tok , const std : : string & alt )
{
return ( tok - > name & &
2018-05-14 13:00:22 +02:00
tok - > str ( ) = = alt & &
2017-05-26 16:45:07 +02:00
tok - > previous & &
tok - > next & &
( tok - > previous - > number | | tok - > previous - > name | | tok - > previous - > op = = ' ) ' ) & &
( tok - > next - > number | | tok - > next - > name | | tok - > next - > op = = ' ( ' ) ) ;
}
2016-07-31 20:48:55 +02:00
2017-05-26 16:45:07 +02:00
static bool isAlternativeUnaryOp ( const simplecpp : : Token * tok , const std : : string & alt )
{
2018-05-14 13:00:22 +02:00
return ( ( tok - > name & & tok - > str ( ) = = alt ) & &
2017-05-26 16:45:07 +02:00
( ! tok - > previous | | tok - > previous - > op = = ' ( ' ) & &
( tok - > next & & ( tok - > next - > name | | tok - > next - > number ) ) ) ;
2016-07-20 12:21:00 +02:00
}
2019-12-29 14:01:19 +01:00
static std : : string replaceAll ( std : : string s , const std : : string & from , const std : : string & to )
{
for ( size_t pos = s . find ( from ) ; pos ! = std : : string : : npos ; pos = s . find ( from , pos + to . size ( ) ) )
s . replace ( pos , from . size ( ) , to ) ;
return s ;
}
2018-05-14 13:00:22 +02:00
const std : : string simplecpp : : Location : : emptyFileName ;
2016-12-06 14:10:57 +01:00
void simplecpp : : Location : : adjust ( const std : : string & str )
{
2022-03-22 21:14:48 +01:00
if ( strpbrk ( str . c_str ( ) , " \r \n " ) = = nullptr ) {
2016-07-30 10:37:55 +02:00
col + = str . size ( ) ;
2016-07-20 12:21:00 +02:00
return ;
}
2016-07-29 13:05:35 +02:00
for ( std : : size_t i = 0U ; i < str . size ( ) ; + + i ) {
2016-07-20 12:21:00 +02:00
col + + ;
if ( str [ i ] = = ' \n ' | | str [ i ] = = ' \r ' ) {
2017-06-21 12:09:50 +02:00
col = 1 ;
2016-07-20 12:21:00 +02:00
line + + ;
if ( str [ i ] = = ' \r ' & & ( i + 1 ) < str . size ( ) & & str [ i + 1 ] = = ' \n ' )
+ + i ;
}
}
}
2016-12-06 14:10:57 +01:00
bool simplecpp : : Token : : isOneOf ( const char ops [ ] ) const
{
2022-03-22 21:14:48 +01:00
return ( op ! = ' \0 ' ) & & ( std : : strchr ( ops , op ) ! = nullptr ) ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
bool simplecpp : : Token : : startsWithOneOf ( const char c [ ] ) const
{
2022-03-22 21:14:48 +01:00
return std : : strchr ( c , string [ 0 ] ) ! = nullptr ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
bool simplecpp : : Token : : endsWithOneOf ( const char c [ ] ) const
{
2022-03-22 21:14:48 +01:00
return std : : strchr ( c , string [ string . size ( ) - 1U ] ) ! = nullptr ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
void simplecpp : : Token : : printAll ( ) const
{
2016-07-25 09:13:59 +02:00
const Token * tok = this ;
while ( tok - > previous )
tok = tok - > previous ;
2016-12-06 14:10:57 +01:00
for ( ; tok ; tok = tok - > next ) {
2016-07-25 09:13:59 +02:00
if ( tok - > previous ) {
std : : cout < < ( sameline ( tok , tok - > previous ) ? ' ' : ' \n ' ) ;
}
2018-05-14 13:00:22 +02:00
std : : cout < < tok - > str ( ) ;
2016-07-25 09:13:59 +02:00
}
std : : cout < < std : : endl ;
}
2016-12-06 14:10:57 +01:00
void simplecpp : : Token : : printOut ( ) const
{
2016-07-25 09:13:59 +02:00
for ( const Token * tok = this ; tok ; tok = tok - > next ) {
if ( tok ! = this ) {
std : : cout < < ( sameline ( tok , tok - > previous ) ? ' ' : ' \n ' ) ;
}
2018-05-14 13:00:22 +02:00
std : : cout < < tok - > str ( ) ;
2016-07-25 09:13:59 +02:00
}
std : : cout < < std : : endl ;
}
2023-09-13 10:30:42 +02:00
// cppcheck-suppress noConstructor - we call init() in the inherited to initialize the private members
2023-03-13 16:11:46 +01:00
class simplecpp : : TokenList : : Stream {
public :
virtual ~ Stream ( ) { }
virtual int get ( ) = 0 ;
virtual int peek ( ) = 0 ;
virtual void unget ( ) = 0 ;
virtual bool good ( ) = 0 ;
unsigned char readChar ( )
{
unsigned char ch = static_cast < unsigned char > ( get ( ) ) ;
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
// character is non-ASCII character then replace it with 0xff
if ( isUtf16 ) {
const unsigned char ch2 = static_cast < unsigned char > ( get ( ) ) ;
const int ch16 = makeUtf16Char ( ch , ch2 ) ;
ch = static_cast < unsigned char > ( ( ( ch16 > = 0x80 ) ? 0xff : ch16 ) ) ;
}
// Handling of newlines..
if ( ch = = ' \r ' ) {
ch = ' \n ' ;
int ch2 = get ( ) ;
if ( isUtf16 ) {
const int c2 = get ( ) ;
ch2 = makeUtf16Char ( ch2 , c2 ) ;
}
if ( ch2 ! = ' \n ' )
ungetChar ( ) ;
}
return ch ;
}
unsigned char peekChar ( )
{
unsigned char ch = static_cast < unsigned char > ( peek ( ) ) ;
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
// character is non-ASCII character then replace it with 0xff
if ( isUtf16 ) {
( void ) get ( ) ;
const unsigned char ch2 = static_cast < unsigned char > ( peek ( ) ) ;
unget ( ) ;
const int ch16 = makeUtf16Char ( ch , ch2 ) ;
ch = static_cast < unsigned char > ( ( ( ch16 > = 0x80 ) ? 0xff : ch16 ) ) ;
}
// Handling of newlines..
if ( ch = = ' \r ' )
ch = ' \n ' ;
return ch ;
}
void ungetChar ( )
{
unget ( ) ;
if ( isUtf16 )
unget ( ) ;
}
protected :
void init ( ) {
// initialize since we use peek() in getAndSkipBOM()
isUtf16 = false ;
bom = getAndSkipBOM ( ) ;
isUtf16 = ( bom = = 0xfeff | | bom = = 0xfffe ) ;
}
private :
inline int makeUtf16Char ( const unsigned char ch , const unsigned char ch2 ) const
{
return ( bom = = 0xfeff ) ? ( ch < < 8 | ch2 ) : ( ch2 < < 8 | ch ) ;
}
unsigned short getAndSkipBOM ( )
{
const int ch1 = peek ( ) ;
// The UTF-16 BOM is 0xfffe or 0xfeff.
if ( ch1 > = 0xfe ) {
( void ) get ( ) ;
const unsigned short byte = ( static_cast < unsigned char > ( ch1 ) < < 8 ) ;
if ( peek ( ) > = 0xfe )
return byte | static_cast < unsigned char > ( get ( ) ) ;
unget ( ) ;
return 0 ;
}
// Skip UTF-8 BOM 0xefbbbf
if ( ch1 = = 0xef ) {
( void ) get ( ) ;
if ( peek ( ) = = 0xbb ) {
( void ) get ( ) ;
if ( peek ( ) = = 0xbf ) {
( void ) get ( ) ;
return 0 ;
}
unget ( ) ;
}
unget ( ) ;
}
return 0 ;
}
unsigned short bom ;
protected :
bool isUtf16 ;
} ;
class StdIStream : public simplecpp : : TokenList : : Stream {
public :
2023-09-13 10:30:42 +02:00
// cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members
EXPLICIT StdIStream ( std : : istream & istr )
2023-03-13 16:11:46 +01:00
: istr ( istr )
{
2023-04-05 21:17:48 +02:00
assert ( istr . good ( ) ) ;
2023-03-13 16:11:46 +01:00
init ( ) ;
}
2023-09-13 10:30:42 +02:00
virtual int get ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
return istr . get ( ) ;
}
2023-09-13 10:30:42 +02:00
virtual int peek ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
return istr . peek ( ) ;
}
2023-09-13 10:30:42 +02:00
virtual void unget ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
istr . unget ( ) ;
}
2023-09-13 10:30:42 +02:00
virtual bool good ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
return istr . good ( ) ;
}
private :
std : : istream & istr ;
} ;
class FileStream : public simplecpp : : TokenList : : Stream {
public :
2023-09-13 10:30:42 +02:00
// cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members
EXPLICIT FileStream ( const std : : string & filename )
2023-03-13 16:11:46 +01:00
: file ( fopen ( filename . c_str ( ) , " rb " ) )
, lastCh ( 0 )
, lastStatus ( 0 )
{
2023-04-05 21:17:48 +02:00
assert ( file ! = nullptr ) ;
2023-03-13 16:11:46 +01:00
init ( ) ;
}
2023-09-13 10:30:42 +02:00
~ FileStream ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
fclose ( file ) ;
file = nullptr ;
}
2023-09-13 10:30:42 +02:00
virtual int get ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
lastStatus = lastCh = fgetc ( file ) ;
return lastCh ;
}
2023-09-13 10:30:42 +02:00
virtual int peek ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
// keep lastCh intact
const int ch = fgetc ( file ) ;
unget_internal ( ch ) ;
return ch ;
}
2023-09-13 10:30:42 +02:00
virtual void unget ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
unget_internal ( lastCh ) ;
}
2023-09-13 10:30:42 +02:00
virtual bool good ( ) OVERRIDE {
2023-03-13 16:11:46 +01:00
return lastStatus ! = EOF ;
}
private :
void unget_internal ( int ch ) {
if ( isUtf16 ) {
// TODO: use ungetc() as well
// UTF-16 has subsequent unget() calls
fseek ( file , - 1 , SEEK_CUR ) ;
}
else
ungetc ( ch , file ) ;
}
2023-09-13 10:30:42 +02:00
FileStream ( const FileStream & ) ;
FileStream & operator = ( const FileStream & ) ;
2023-03-13 16:11:46 +01:00
FILE * file ;
int lastCh ;
int lastStatus ;
} ;
2022-03-22 21:14:48 +01:00
simplecpp : : TokenList : : TokenList ( std : : vector < std : : string > & filenames ) : frontToken ( nullptr ) , backToken ( nullptr ) , files ( filenames ) { }
2016-07-20 12:21:00 +02:00
simplecpp : : TokenList : : TokenList ( std : : istream & istr , std : : vector < std : : string > & filenames , const std : : string & filename , OutputList * outputList )
2022-03-22 21:14:48 +01:00
: frontToken ( nullptr ) , backToken ( nullptr ) , files ( filenames )
2016-12-06 14:10:57 +01:00
{
2023-03-13 16:11:46 +01:00
StdIStream stream ( istr ) ;
readfile ( stream , filename , outputList ) ;
}
simplecpp : : TokenList : : TokenList ( const std : : string & filename , std : : vector < std : : string > & filenames , OutputList * outputList )
: frontToken ( nullptr ) , backToken ( nullptr ) , files ( filenames )
{
FileStream stream ( filename ) ;
readfile ( stream , filename , outputList ) ;
2016-07-20 12:21:00 +02:00
}
2022-03-22 21:14:48 +01:00
simplecpp : : TokenList : : TokenList ( const TokenList & other ) : frontToken ( nullptr ) , backToken ( nullptr ) , files ( other . files )
2016-12-06 14:10:57 +01:00
{
2016-07-20 12:21:00 +02:00
* this = other ;
}
2019-05-03 18:49:48 +02:00
# if __cplusplus >= 201103L
2022-09-30 07:26:48 +02:00
simplecpp : : TokenList : : TokenList ( TokenList & & other ) : frontToken ( nullptr ) , backToken ( nullptr ) , files ( other . files )
2019-05-03 18:49:48 +02:00
{
* this = std : : move ( other ) ;
}
# endif
2016-12-06 14:10:57 +01:00
simplecpp : : TokenList : : ~ TokenList ( )
{
2016-07-20 12:21:00 +02:00
clear ( ) ;
}
2017-08-13 13:59:09 +02:00
simplecpp : : TokenList & simplecpp : : TokenList : : operator = ( const TokenList & other )
2016-12-06 14:10:57 +01:00
{
2017-08-13 13:59:09 +02:00
if ( this ! = & other ) {
clear ( ) ;
2022-03-22 21:14:48 +01:00
files = other . files ;
2017-08-13 13:59:09 +02:00
for ( const Token * tok = other . cfront ( ) ; tok ; tok = tok - > next )
push_back ( new Token ( * tok ) ) ;
sizeOfType = other . sizeOfType ;
}
return * this ;
2016-07-20 12:21:00 +02:00
}
2019-05-03 18:49:48 +02:00
# if __cplusplus >= 201103L
simplecpp : : TokenList & simplecpp : : TokenList : : operator = ( TokenList & & other )
{
if ( this ! = & other ) {
clear ( ) ;
2022-03-21 19:11:26 +01:00
frontToken = other . frontToken ;
2022-03-22 21:14:48 +01:00
other . frontToken = nullptr ;
backToken = other . backToken ;
other . backToken = nullptr ;
files = other . files ;
2019-05-03 18:49:48 +02:00
sizeOfType = std : : move ( other . sizeOfType ) ;
}
return * this ;
}
# endif
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : clear ( )
{
2022-03-22 21:14:48 +01:00
backToken = nullptr ;
2016-07-29 08:46:38 +02:00
while ( frontToken ) {
2022-09-30 07:26:48 +02:00
Token * const next = frontToken - > next ;
2016-07-29 08:46:38 +02:00
delete frontToken ;
frontToken = next ;
2016-07-20 12:21:00 +02:00
}
2016-07-20 15:04:03 +02:00
sizeOfType . clear ( ) ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : push_back ( Token * tok )
{
2016-07-29 08:46:38 +02:00
if ( ! frontToken )
frontToken = tok ;
2016-07-20 12:21:00 +02:00
else
2016-07-29 08:46:38 +02:00
backToken - > next = tok ;
tok - > previous = backToken ;
backToken = tok ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : dump ( ) const
{
2016-07-23 09:26:06 +02:00
std : : cout < < stringify ( ) < < std : : endl ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
std : : string simplecpp : : TokenList : : stringify ( ) const
{
2016-07-20 12:21:00 +02:00
std : : ostringstream ret ;
Location loc ( files ) ;
2016-07-29 08:46:38 +02:00
for ( const Token * tok = cfront ( ) ; tok ; tok = tok - > next ) {
2016-08-11 19:00:35 +02:00
if ( tok - > location . line < loc . line | | tok - > location . fileIndex ! = loc . fileIndex ) {
ret < < " \n #line " < < tok - > location . line < < " \" " < < tok - > location . file ( ) < < " \" \n " ;
loc = tok - > location ;
}
2016-07-20 12:21:00 +02:00
while ( tok - > location . line > loc . line ) {
ret < < ' \n ' ;
loc . line + + ;
}
if ( sameline ( tok - > previous , tok ) )
ret < < ' ' ;
2018-05-14 13:00:22 +02:00
ret < < tok - > str ( ) ;
2016-07-20 12:21:00 +02:00
2018-05-14 13:00:22 +02:00
loc . adjust ( tok - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
}
return ret . str ( ) ;
}
2017-05-26 16:45:07 +02:00
static bool isNameChar ( unsigned char ch )
2016-12-06 14:10:57 +01:00
{
2016-07-29 13:05:35 +02:00
return std : : isalnum ( ch ) | | ch = = ' _ ' | | ch = = ' $ ' ;
2016-07-29 20:54:11 +02:00
}
2016-07-29 13:05:35 +02:00
2016-12-06 14:10:57 +01:00
static std : : string escapeString ( const std : : string & str )
{
2016-08-11 19:00:35 +02:00
std : : ostringstream ostr ;
ostr < < ' \" ' ;
for ( std : : size_t i = 1U ; i < str . size ( ) - 1 ; + + i ) {
2022-09-30 07:26:48 +02:00
const char c = str [ i ] ;
2016-08-11 19:00:35 +02:00
if ( c = = ' \\ ' | | c = = ' \" ' | | c = = ' \' ' )
ostr < < ' \\ ' ;
ostr < < c ;
}
ostr < < ' \" ' ;
return ostr . str ( ) ;
}
2016-12-06 14:10:57 +01:00
static void portabilityBackslash ( simplecpp : : OutputList * outputList , const std : : vector < std : : string > & files , const simplecpp : : Location & location )
{
2016-09-03 12:29:45 +02:00
if ( ! outputList )
return ;
simplecpp : : Output err ( files ) ;
err . type = simplecpp : : Output : : PORTABILITY_BACKSLASH ;
err . location = location ;
err . msg = " Combination 'backslash space newline' is not portable. " ;
outputList - > push_back ( err ) ;
}
2019-03-10 08:47:27 +01:00
static bool isStringLiteralPrefix ( const std : : string & str )
2018-01-14 15:18:21 +01:00
{
2019-03-10 08:47:27 +01:00
return str = = " u " | | str = = " U " | | str = = " L " | | str = = " u8 " | |
str = = " R " | | str = = " uR " | | str = = " UR " | | str = = " LR " | | str = = " u8R " ;
2018-01-14 15:18:21 +01:00
}
2019-05-03 18:49:48 +02:00
void simplecpp : : TokenList : : lineDirective ( unsigned int fileIndex , unsigned int line , Location * location )
{
if ( fileIndex ! = location - > fileIndex | | line > = location - > line ) {
location - > fileIndex = fileIndex ;
location - > line = line ;
return ;
}
if ( line + 2 > = location - > line ) {
location - > line = line ;
while ( cback ( ) - > op ! = ' # ' )
deleteToken ( back ( ) ) ;
deleteToken ( back ( ) ) ;
return ;
}
}
2022-03-22 21:14:48 +01:00
static const std : : string COMMENT_END ( " */ " ) ;
2023-03-13 16:11:46 +01:00
void simplecpp : : TokenList : : readfile ( Stream & stream , const std : : string & filename , OutputList * outputList )
2016-07-20 12:21:00 +02:00
{
std : : stack < simplecpp : : Location > loc ;
unsigned int multiline = 0U ;
2022-03-22 21:14:48 +01:00
const Token * oldLastToken = nullptr ;
2016-07-20 12:21:00 +02:00
Location location ( files ) ;
location . fileIndex = fileIndex ( filename ) ;
location . line = 1U ;
2016-07-30 10:37:55 +02:00
location . col = 1U ;
2023-03-13 16:11:46 +01:00
while ( stream . good ( ) ) {
unsigned char ch = stream . readChar ( ) ;
if ( ! stream . good ( ) )
2016-07-20 12:21:00 +02:00
break ;
2017-09-12 22:42:10 +02:00
if ( ch > = 0x80 ) {
if ( outputList ) {
simplecpp : : Output err ( files ) ;
err . type = simplecpp : : Output : : UNHANDLED_CHAR_ERROR ;
err . location = location ;
std : : ostringstream s ;
2022-03-22 21:14:48 +01:00
s < < static_cast < int > ( ch ) ;
2017-09-12 22:42:10 +02:00
err . msg = " The code contains unhandled character(s) (character code= " + s . str ( ) + " ). Neither unicode nor extended ascii is supported. " ;
outputList - > push_back ( err ) ;
}
clear ( ) ;
return ;
}
2016-07-20 12:21:00 +02:00
if ( ch = = ' \n ' ) {
2016-07-29 08:46:38 +02:00
if ( cback ( ) & & cback ( ) - > op = = ' \\ ' ) {
2016-09-03 12:29:45 +02:00
if ( location . col > cback ( ) - > location . col + 1U )
portabilityBackslash ( outputList , files , cback ( ) - > location ) ;
2016-07-20 12:21:00 +02:00
+ + multiline ;
2016-07-29 08:46:38 +02:00
deleteToken ( back ( ) ) ;
2016-07-20 12:21:00 +02:00
} else {
location . line + = multiline + 1 ;
multiline = 0U ;
}
2016-08-06 14:56:07 +02:00
if ( ! multiline )
location . col = 1 ;
2016-07-20 12:21:00 +02:00
2016-07-29 08:46:38 +02:00
if ( oldLastToken ! = cback ( ) ) {
oldLastToken = cback ( ) ;
2022-03-22 21:14:48 +01:00
if ( ! isLastLinePreprocessor ( ) )
continue ;
2016-07-20 12:21:00 +02:00
const std : : string lastline ( lastLine ( ) ) ;
if ( lastline = = " # file %str% " ) {
2021-12-16 21:18:05 +01:00
const Token * strtok = cback ( ) ;
while ( strtok - > comment )
strtok = strtok - > previous ;
2016-07-20 12:21:00 +02:00
loc . push ( location ) ;
2021-12-16 21:18:05 +01:00
location . fileIndex = fileIndex ( strtok - > str ( ) . substr ( 1U , strtok - > str ( ) . size ( ) - 2U ) ) ;
2016-07-20 12:21:00 +02:00
location . line = 1U ;
2016-11-06 12:29:13 +01:00
} else if ( lastline = = " # line %num% " ) {
2021-12-16 21:18:05 +01:00
const Token * numtok = cback ( ) ;
while ( numtok - > comment )
numtok = numtok - > previous ;
lineDirective ( location . fileIndex , std : : atol ( numtok - > str ( ) . c_str ( ) ) , & location ) ;
2019-05-03 18:49:48 +02:00
} else if ( lastline = = " # %num% %str% " | | lastline = = " # line %num% %str% " ) {
2021-12-16 21:18:05 +01:00
const Token * strtok = cback ( ) ;
while ( strtok - > comment )
strtok = strtok - > previous ;
const Token * numtok = strtok - > previous ;
while ( numtok - > comment )
numtok = numtok - > previous ;
lineDirective ( fileIndex ( replaceAll ( strtok - > str ( ) . substr ( 1U , strtok - > str ( ) . size ( ) - 2U ) , " \\ \\ " , " \\ " ) ) ,
std : : atol ( numtok - > str ( ) . c_str ( ) ) , & location ) ;
2016-07-20 12:21:00 +02:00
}
// #endfile
else if ( lastline = = " # endfile " & & ! loc . empty ( ) ) {
location = loc . top ( ) ;
loc . pop ( ) ;
}
}
continue ;
}
2023-11-03 13:55:54 +01:00
if ( ch < = ' ' ) {
2016-07-30 10:37:55 +02:00
location . col + + ;
2016-07-20 12:21:00 +02:00
continue ;
2016-07-30 10:37:55 +02:00
}
2016-07-20 12:21:00 +02:00
TokenString currentToken ;
2022-12-09 07:18:13 +01:00
if ( cback ( ) & & cback ( ) - > location . line = = location . line & & cback ( ) - > previous & & cback ( ) - > previous - > op = = ' # ' & & isLastLinePreprocessor ( ) & & ( lastLine ( ) = = " # error " | | lastLine ( ) = = " # warning " ) ) {
2019-02-06 16:26:59 +01:00
char prev = ' ' ;
2023-03-13 16:11:46 +01:00
while ( stream . good ( ) & & ( prev = = ' \\ ' | | ( ch ! = ' \r ' & & ch ! = ' \n ' ) ) ) {
2018-02-11 15:48:37 +01:00
currentToken + = ch ;
2019-02-06 16:26:59 +01:00
prev = ch ;
2023-03-13 16:11:46 +01:00
ch = stream . readChar ( ) ;
2018-02-11 15:48:37 +01:00
}
2023-03-13 16:11:46 +01:00
stream . ungetChar ( ) ;
2018-02-11 15:48:37 +01:00
push_back ( new Token ( currentToken , location ) ) ;
2019-02-06 16:26:59 +01:00
location . adjust ( currentToken ) ;
2018-02-11 15:48:37 +01:00
continue ;
}
2016-07-20 12:21:00 +02:00
// number or name
2016-07-29 13:05:35 +02:00
if ( isNameChar ( ch ) ) {
2017-09-08 23:20:39 +02:00
const bool num = std : : isdigit ( ch ) ;
2023-03-13 16:11:46 +01:00
while ( stream . good ( ) & & isNameChar ( ch ) ) {
2016-07-20 12:21:00 +02:00
currentToken + = ch ;
2023-03-13 16:11:46 +01:00
ch = stream . readChar ( ) ;
if ( num & & ch = = ' \' ' & & isNameChar ( stream . peekChar ( ) ) )
ch = stream . readChar ( ) ;
2016-07-20 12:21:00 +02:00
}
2016-07-28 09:26:23 +02:00
2023-03-13 16:11:46 +01:00
stream . ungetChar ( ) ;
2016-07-20 12:21:00 +02:00
}
// comment
2023-03-13 16:11:46 +01:00
else if ( ch = = ' / ' & & stream . peekChar ( ) = = ' / ' ) {
while ( stream . good ( ) & & ch ! = ' \r ' & & ch ! = ' \n ' ) {
2016-07-20 12:21:00 +02:00
currentToken + = ch ;
2023-03-13 16:11:46 +01:00
ch = stream . readChar ( ) ;
2016-07-20 12:21:00 +02:00
}
2016-09-03 12:29:45 +02:00
const std : : string : : size_type pos = currentToken . find_last_not_of ( " \t " ) ;
if ( pos < currentToken . size ( ) - 1U & & currentToken [ pos ] = = ' \\ ' )
portabilityBackslash ( outputList , files , location ) ;
2016-07-20 12:21:00 +02:00
if ( currentToken [ currentToken . size ( ) - 1U ] = = ' \\ ' ) {
2016-07-30 10:37:55 +02:00
+ + multiline ;
2021-02-21 19:13:16 +01:00
currentToken . erase ( currentToken . size ( ) - 1U ) ;
2016-07-20 12:21:00 +02:00
} else {
2023-03-13 16:11:46 +01:00
stream . ungetChar ( ) ;
2016-07-20 12:21:00 +02:00
}
}
// comment
2023-03-13 16:11:46 +01:00
else if ( ch = = ' / ' & & stream . peekChar ( ) = = ' * ' ) {
2016-07-20 12:21:00 +02:00
currentToken = " /* " ;
2023-03-13 16:11:46 +01:00
( void ) stream . readChar ( ) ;
ch = stream . readChar ( ) ;
while ( stream . good ( ) ) {
2016-07-20 12:21:00 +02:00
currentToken + = ch ;
2022-03-22 21:14:48 +01:00
if ( currentToken . size ( ) > = 4U & & endsWith ( currentToken , COMMENT_END ) )
2016-07-20 12:21:00 +02:00
break ;
2023-03-13 16:11:46 +01:00
ch = stream . readChar ( ) ;
2016-07-20 12:21:00 +02:00
}
2016-07-30 10:37:55 +02:00
// multiline..
2016-08-06 11:38:20 +02:00
2016-07-30 10:37:55 +02:00
std : : string : : size_type pos = 0 ;
while ( ( pos = currentToken . find ( " \\ \n " , pos ) ) ! = std : : string : : npos ) {
currentToken . erase ( pos , 2 ) ;
+ + multiline ;
}
2022-12-09 07:18:13 +01:00
if ( multiline | | isLastLinePreprocessor ( ) ) {
2016-08-06 11:38:20 +02:00
pos = 0 ;
2016-12-04 12:10:28 +01:00
while ( ( pos = currentToken . find ( ' \n ' , pos ) ) ! = std : : string : : npos ) {
2016-08-06 11:38:20 +02:00
currentToken . erase ( pos , 1 ) ;
+ + multiline ;
}
}
2016-07-20 12:21:00 +02:00
}
// string / char literal
else if ( ch = = ' \" ' | | ch = = ' \' ' ) {
2019-03-11 18:18:00 +01:00
std : : string prefix ;
2019-03-31 07:49:43 +02:00
if ( cback ( ) & & cback ( ) - > name & & isStringLiteralPrefix ( cback ( ) - > str ( ) ) & &
2019-05-03 18:49:48 +02:00
( ( cback ( ) - > location . col + cback ( ) - > str ( ) . size ( ) ) = = location . col ) & &
( cback ( ) - > location . line = = location . line ) ) {
2019-03-11 18:18:00 +01:00
prefix = cback ( ) - > str ( ) ;
}
// C++11 raw string literal
if ( ch = = ' \" ' & & ! prefix . empty ( ) & & * cback ( ) - > str ( ) . rbegin ( ) = = ' R ' ) {
2016-07-28 09:26:23 +02:00
std : : string delim ;
2019-03-10 08:47:27 +01:00
currentToken = ch ;
2021-02-21 19:13:16 +01:00
prefix . resize ( prefix . size ( ) - 1 ) ;
2023-03-13 16:11:46 +01:00
ch = stream . readChar ( ) ;
while ( stream . good ( ) & & ch ! = ' ( ' & & ch ! = ' \n ' ) {
2019-03-11 18:18:00 +01:00
delim + = ch ;
2023-03-13 16:11:46 +01:00
ch = stream . readChar ( ) ;
2019-03-11 18:18:00 +01:00
}
2023-03-13 16:11:46 +01:00
if ( ! stream . good ( ) | | ch = = ' \n ' ) {
2019-03-11 18:18:00 +01:00
if ( outputList ) {
Output err ( files ) ;
err . type = Output : : SYNTAX_ERROR ;
err . location = location ;
err . msg = " Invalid newline in raw string delimiter. " ;
outputList - > push_back ( err ) ;
2019-03-10 08:47:27 +01:00
}
2019-03-11 18:18:00 +01:00
return ;
2016-07-28 09:26:23 +02:00
}
2019-03-11 18:18:00 +01:00
const std : : string endOfRawString ( ' ) ' + delim + currentToken ) ;
2023-03-13 16:11:46 +01:00
while ( stream . good ( ) & & ! ( endsWith ( currentToken , endOfRawString ) & & currentToken . size ( ) > 1 ) )
currentToken + = stream . readChar ( ) ;
2019-03-11 18:18:00 +01:00
if ( ! endsWith ( currentToken , endOfRawString ) ) {
if ( outputList ) {
Output err ( files ) ;
err . type = Output : : SYNTAX_ERROR ;
err . location = location ;
err . msg = " Raw string missing terminating delimiter. " ;
outputList - > push_back ( err ) ;
}
2016-07-28 09:26:23 +02:00
return ;
2019-03-11 18:18:00 +01:00
}
2016-07-28 09:26:23 +02:00
currentToken . erase ( currentToken . size ( ) - endOfRawString . size ( ) , endOfRawString . size ( ) - 1U ) ;
2019-03-11 18:18:00 +01:00
currentToken = escapeString ( currentToken ) ;
2019-03-10 08:47:27 +01:00
currentToken . insert ( 0 , prefix ) ;
back ( ) - > setstr ( currentToken ) ;
2017-06-21 12:09:50 +02:00
location . adjust ( currentToken ) ;
if ( currentToken . find_first_of ( " \r \n " ) = = std : : string : : npos )
location . col + = 2 + 2 * delim . size ( ) ;
else
location . col + = 1 + delim . size ( ) ;
2019-03-11 18:18:00 +01:00
2016-07-28 09:26:23 +02:00
continue ;
}
2023-03-13 16:11:46 +01:00
currentToken = readUntil ( stream , location , ch , ch , outputList ) ;
2016-07-20 12:21:00 +02:00
if ( currentToken . size ( ) < 2U )
2019-03-11 18:18:00 +01:00
// Error is reported by readUntil()
2016-07-20 12:21:00 +02:00
return ;
2017-05-28 15:23:15 +02:00
std : : string s = currentToken ;
std : : string : : size_type pos ;
2018-02-14 22:14:42 +01:00
int newlines = 0 ;
2017-05-28 15:23:15 +02:00
while ( ( pos = s . find_first_of ( " \r \n " ) ) ! = std : : string : : npos ) {
s . erase ( pos , 1 ) ;
2018-02-14 22:14:42 +01:00
newlines + + ;
2017-05-28 15:23:15 +02:00
}
2019-03-11 18:18:00 +01:00
if ( prefix . empty ( ) )
push_back ( new Token ( s , location ) ) ; // push string without newlines
else
back ( ) - > setstr ( prefix + s ) ;
2017-05-28 15:23:15 +02:00
2022-12-09 07:18:13 +01:00
if ( newlines > 0 & & isLastLinePreprocessor ( ) & & lastLine ( ) . compare ( 0 , 9 , " # define " ) = = 0 ) {
2018-02-14 22:14:42 +01:00
multiline + = newlines ;
location . adjust ( s ) ;
} else {
location . adjust ( currentToken ) ;
}
2017-05-28 15:23:15 +02:00
continue ;
2016-07-20 12:21:00 +02:00
}
else {
currentToken + = ch ;
}
2022-12-09 07:18:13 +01:00
if ( * currentToken . begin ( ) = = ' < ' & & isLastLinePreprocessor ( ) & & lastLine ( ) = = " # include " ) {
2023-03-13 16:11:46 +01:00
currentToken = readUntil ( stream , location , ' < ' , ' > ' , outputList ) ;
2016-07-20 12:21:00 +02:00
if ( currentToken . size ( ) < 2U )
return ;
}
push_back ( new Token ( currentToken , location ) ) ;
2016-08-06 14:56:07 +02:00
if ( multiline )
location . col + = currentToken . size ( ) ;
else
location . adjust ( currentToken ) ;
2016-07-20 12:21:00 +02:00
}
combineOperators ( ) ;
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : constFold ( )
{
2016-07-29 08:46:38 +02:00
while ( cfront ( ) ) {
2016-07-20 12:21:00 +02:00
// goto last '('
2016-07-29 08:46:38 +02:00
Token * tok = back ( ) ;
2016-07-20 12:21:00 +02:00
while ( tok & & tok - > op ! = ' ( ' )
tok = tok - > previous ;
// no '(', goto first token
if ( ! tok )
2016-07-29 08:46:38 +02:00
tok = front ( ) ;
2016-07-20 12:21:00 +02:00
// Constant fold expression
constFoldUnaryNotPosNeg ( tok ) ;
constFoldMulDivRem ( tok ) ;
constFoldAddSub ( tok ) ;
2017-09-08 23:20:39 +02:00
constFoldShift ( tok ) ;
2016-07-20 12:21:00 +02:00
constFoldComparison ( tok ) ;
constFoldBitwise ( tok ) ;
constFoldLogicalOp ( tok ) ;
constFoldQuestionOp ( & tok ) ;
// If there is no '(' we are done with the constant folding
if ( tok - > op ! = ' ( ' )
break ;
if ( ! tok - > next | | ! tok - > next - > next | | tok - > next - > next - > op ! = ' ) ' )
break ;
tok = tok - > next ;
deleteToken ( tok - > previous ) ;
deleteToken ( tok - > next ) ;
}
}
2017-05-26 16:45:07 +02:00
static bool isFloatSuffix ( const simplecpp : : Token * tok )
{
2018-05-14 13:00:22 +02:00
if ( ! tok | | tok - > str ( ) . size ( ) ! = 1U )
2017-05-18 21:40:47 +02:00
return false ;
2018-05-14 13:00:22 +02:00
const char c = std : : tolower ( tok - > str ( ) [ 0 ] ) ;
2017-05-26 16:45:07 +02:00
return c = = ' f ' | | c = = ' l ' ;
2017-05-18 21:40:47 +02:00
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : combineOperators ( )
{
2018-04-01 09:06:13 +02:00
std : : stack < bool > executableScope ;
executableScope . push ( false ) ;
2016-07-29 08:46:38 +02:00
for ( Token * tok = front ( ) ; tok ; tok = tok - > next ) {
2018-04-01 09:06:13 +02:00
if ( tok - > op = = ' { ' ) {
if ( executableScope . top ( ) ) {
executableScope . push ( true ) ;
continue ;
}
const Token * prev = tok - > previous ;
while ( prev & & prev - > isOneOf ( " ;{}() " ) )
prev = prev - > previous ;
executableScope . push ( prev & & prev - > op = = ' ) ' ) ;
continue ;
}
if ( tok - > op = = ' } ' ) {
if ( executableScope . size ( ) > 1 )
executableScope . pop ( ) ;
continue ;
}
2016-07-20 12:21:00 +02:00
if ( tok - > op = = ' . ' ) {
2019-09-04 08:07:30 +02:00
// ellipsis ...
if ( tok - > next & & tok - > next - > op = = ' . ' & & tok - > next - > location . col = = ( tok - > location . col + 1 ) & &
tok - > next - > next & & tok - > next - > next - > op = = ' . ' & & tok - > next - > next - > location . col = = ( tok - > location . col + 2 ) ) {
tok - > setstr ( " ... " ) ;
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
2017-05-18 21:40:47 +02:00
continue ;
2019-09-04 08:07:30 +02:00
}
2016-07-20 12:21:00 +02:00
// float literals..
2023-09-13 10:30:42 +02:00
if ( tok - > previous & & tok - > previous - > number & & sameline ( tok - > previous , tok ) ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > previous - > str ( ) + ' . ' ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > previous ) ;
2023-09-26 15:58:16 +02:00
if ( sameline ( tok , tok - > next ) & & ( isFloatSuffix ( tok - > next ) | | ( tok - > next & & tok - > next - > startsWithOneOf ( " AaBbCcDdEeFfPp " ) ) ) ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
}
}
if ( tok - > next & & tok - > next - > number ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
}
}
// match: [0-9.]+E [+-] [0-9]+
2018-05-14 13:00:22 +02:00
const char lastChar = tok - > str ( ) [ tok - > str ( ) . size ( ) - 1 ] ;
2019-10-26 17:30:04 +02:00
if ( tok - > number & & ! isOct ( tok - > str ( ) ) & &
( ( ! isHex ( tok - > str ( ) ) & & ( lastChar = = ' E ' | | lastChar = = ' e ' ) ) | |
( isHex ( tok - > str ( ) ) & & ( lastChar = = ' P ' | | lastChar = = ' p ' ) ) ) & &
tok - > next & & tok - > next - > isOneOf ( " +- " ) & & tok - > next - > next & & tok - > next - > next - > number ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > op + tok - > next - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
if ( tok - > op = = ' \0 ' | | ! tok - > next | | tok - > next - > op = = ' \0 ' )
continue ;
2016-08-11 19:00:35 +02:00
if ( ! sameline ( tok , tok - > next ) )
continue ;
if ( tok - > location . col + 1U ! = tok - > next - > location . col )
continue ;
2016-07-20 12:21:00 +02:00
if ( tok - > next - > op = = ' = ' & & tok - > isOneOf ( " =!<>+-*/%&|^ " ) ) {
2018-04-01 09:06:13 +02:00
if ( tok - > op = = ' & ' & & ! executableScope . top ( ) ) {
// don't combine &= if it is a anonymous reference parameter with default value:
// void f(x&=2)
int indentlevel = 0 ;
const Token * start = tok ;
while ( indentlevel > = 0 & & start ) {
if ( start - > op = = ' ) ' )
+ + indentlevel ;
else if ( start - > op = = ' ( ' )
- - indentlevel ;
else if ( start - > isOneOf ( " ;{} " ) )
break ;
start = start - > previous ;
}
if ( indentlevel = = - 1 & & start ) {
2022-09-30 07:26:48 +02:00
const Token * const ftok = start ;
2018-04-01 09:06:13 +02:00
bool isFuncDecl = ftok - > name ;
while ( isFuncDecl ) {
2018-05-14 13:00:22 +02:00
if ( ! start - > name & & start - > str ( ) ! = " :: " & & start - > op ! = ' * ' & & start - > op ! = ' & ' )
2018-04-01 09:06:13 +02:00
isFuncDecl = false ;
if ( ! start - > previous )
break ;
if ( start - > previous - > isOneOf ( " ;{}: " ) )
break ;
start = start - > previous ;
}
isFuncDecl & = start ! = ftok & & start - > name ;
if ( isFuncDecl ) {
// TODO: we could loop through the parameters here and check if they are correct.
continue ;
}
}
}
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + " = " ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
} else if ( ( tok - > op = = ' | ' | | tok - > op = = ' & ' ) & & tok - > op = = tok - > next - > op ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
} else if ( tok - > op = = ' : ' & & tok - > next - > op = = ' : ' ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
} else if ( tok - > op = = ' - ' & & tok - > next - > op = = ' > ' ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
} else if ( ( tok - > op = = ' < ' | | tok - > op = = ' > ' ) & & tok - > op = = tok - > next - > op ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
2019-09-25 20:19:26 +02:00
if ( tok - > next & & tok - > next - > op = = ' = ' & & tok - > next - > next & & tok - > next - > next - > op ! = ' = ' ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
}
} else if ( ( tok - > op = = ' + ' | | tok - > op = = ' - ' ) & & tok - > op = = tok - > next - > op ) {
if ( tok - > location . col + 1U ! = tok - > next - > location . col )
continue ;
if ( tok - > previous & & tok - > previous - > number )
continue ;
if ( tok - > next - > next & & tok - > next - > next - > number )
continue ;
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > str ( ) + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
}
}
}
2018-01-13 18:08:23 +01:00
static const std : : string COMPL ( " compl " ) ;
2016-12-06 14:10:57 +01:00
static const std : : string NOT ( " not " ) ;
void simplecpp : : TokenList : : constFoldUnaryNotPosNeg ( simplecpp : : Token * tok )
{
2016-07-20 12:21:00 +02:00
for ( ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
2016-07-31 20:48:55 +02:00
// "not" might be !
if ( isAlternativeUnaryOp ( tok , NOT ) )
tok - > op = ' ! ' ;
2018-01-13 18:08:23 +01:00
// "compl" might be ~
else if ( isAlternativeUnaryOp ( tok , COMPL ) )
tok - > op = ' ~ ' ;
2016-07-31 20:48:55 +02:00
2016-07-20 12:21:00 +02:00
if ( tok - > op = = ' ! ' & & tok - > next & & tok - > next - > number ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > next - > str ( ) = = " 0 " ? " 1 " : " 0 " ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
2018-01-13 18:08:23 +01:00
} else if ( tok - > op = = ' ~ ' & & tok - > next & & tok - > next - > number ) {
2018-05-14 13:00:22 +02:00
tok - > setstr ( toString ( ~ stringToLL ( tok - > next - > str ( ) ) ) ) ;
2018-01-13 18:08:23 +01:00
deleteToken ( tok - > next ) ;
2016-12-06 14:10:57 +01:00
} else {
2016-07-20 12:21:00 +02:00
if ( tok - > previous & & ( tok - > previous - > number | | tok - > previous - > name ) )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
switch ( tok - > op ) {
case ' + ' :
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
break ;
case ' - ' :
2018-05-14 13:00:22 +02:00
tok - > setstr ( tok - > op + tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
break ;
}
}
}
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : constFoldMulDivRem ( Token * tok )
{
2016-07-20 12:21:00 +02:00
for ( ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
if ( ! tok - > previous | | ! tok - > previous - > number )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
long long result ;
if ( tok - > op = = ' * ' )
2018-05-14 13:00:22 +02:00
result = ( stringToLL ( tok - > previous - > str ( ) ) * stringToLL ( tok - > next - > str ( ) ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > op = = ' / ' | | tok - > op = = ' % ' ) {
2022-09-30 07:26:48 +02:00
const long long rhs = stringToLL ( tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
if ( rhs = = 0 )
throw std : : overflow_error ( " division/modulo by zero " ) ;
2022-09-30 07:26:48 +02:00
const long long lhs = stringToLL ( tok - > previous - > str ( ) ) ;
2016-07-20 20:40:16 +02:00
if ( rhs = = - 1 & & lhs = = std : : numeric_limits < long long > : : min ( ) )
throw std : : overflow_error ( " division overflow " ) ;
2016-07-20 12:21:00 +02:00
if ( tok - > op = = ' / ' )
2016-07-20 20:40:16 +02:00
result = ( lhs / rhs ) ;
2016-07-20 12:21:00 +02:00
else
2016-07-20 20:40:16 +02:00
result = ( lhs % rhs ) ;
2016-12-06 14:10:57 +01:00
} else
2016-07-20 12:21:00 +02:00
continue ;
tok = tok - > previous ;
2016-07-20 20:03:27 +02:00
tok - > setstr ( toString ( result ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : constFoldAddSub ( Token * tok )
{
2016-07-20 12:21:00 +02:00
for ( ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
if ( ! tok - > previous | | ! tok - > previous - > number )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
long long result ;
if ( tok - > op = = ' + ' )
2018-05-14 13:00:22 +02:00
result = stringToLL ( tok - > previous - > str ( ) ) + stringToLL ( tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > op = = ' - ' )
2018-05-14 13:00:22 +02:00
result = stringToLL ( tok - > previous - > str ( ) ) - stringToLL ( tok - > next - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
else
continue ;
tok = tok - > previous ;
2016-07-20 20:03:27 +02:00
tok - > setstr ( toString ( result ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
}
2017-09-08 23:20:39 +02:00
void simplecpp : : TokenList : : constFoldShift ( Token * tok )
{
for ( ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
if ( ! tok - > previous | | ! tok - > previous - > number )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
long long result ;
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) = = " << " )
result = stringToLL ( tok - > previous - > str ( ) ) < < stringToLL ( tok - > next - > str ( ) ) ;
else if ( tok - > str ( ) = = " >> " )
result = stringToLL ( tok - > previous - > str ( ) ) > > stringToLL ( tok - > next - > str ( ) ) ;
2017-09-08 23:20:39 +02:00
else
continue ;
tok = tok - > previous ;
tok - > setstr ( toString ( result ) ) ;
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
}
2016-12-06 14:10:57 +01:00
static const std : : string NOTEQ ( " not_eq " ) ;
void simplecpp : : TokenList : : constFoldComparison ( Token * tok )
{
2016-07-20 12:21:00 +02:00
for ( ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
2016-07-31 20:48:55 +02:00
if ( isAlternativeBinaryOp ( tok , NOTEQ ) )
tok - > setstr ( " != " ) ;
2016-07-20 12:21:00 +02:00
if ( ! tok - > startsWithOneOf ( " <>=! " ) )
continue ;
if ( ! tok - > previous | | ! tok - > previous - > number )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
int result ;
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) = = " == " )
result = ( stringToLL ( tok - > previous - > str ( ) ) = = stringToLL ( tok - > next - > str ( ) ) ) ;
else if ( tok - > str ( ) = = " != " )
result = ( stringToLL ( tok - > previous - > str ( ) ) ! = stringToLL ( tok - > next - > str ( ) ) ) ;
else if ( tok - > str ( ) = = " > " )
result = ( stringToLL ( tok - > previous - > str ( ) ) > stringToLL ( tok - > next - > str ( ) ) ) ;
else if ( tok - > str ( ) = = " >= " )
result = ( stringToLL ( tok - > previous - > str ( ) ) > = stringToLL ( tok - > next - > str ( ) ) ) ;
else if ( tok - > str ( ) = = " < " )
result = ( stringToLL ( tok - > previous - > str ( ) ) < stringToLL ( tok - > next - > str ( ) ) ) ;
else if ( tok - > str ( ) = = " <= " )
result = ( stringToLL ( tok - > previous - > str ( ) ) < = stringToLL ( tok - > next - > str ( ) ) ) ;
2016-07-20 12:21:00 +02:00
else
continue ;
tok = tok - > previous ;
2016-07-20 20:03:27 +02:00
tok - > setstr ( toString ( result ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
}
2016-12-06 14:10:57 +01:00
static const std : : string BITAND ( " bitand " ) ;
static const std : : string BITOR ( " bitor " ) ;
static const std : : string XOR ( " xor " ) ;
2016-07-20 12:21:00 +02:00
void simplecpp : : TokenList : : constFoldBitwise ( Token * tok )
{
Token * const tok1 = tok ;
for ( const char * op = " &^| " ; * op ; op + + ) {
2020-07-03 11:42:58 +02:00
const std : : string * alternativeOp ;
2016-07-23 09:26:06 +02:00
if ( * op = = ' & ' )
2020-07-03 11:42:58 +02:00
alternativeOp = & BITAND ;
2016-07-23 09:26:06 +02:00
else if ( * op = = ' | ' )
2020-07-03 11:42:58 +02:00
alternativeOp = & BITOR ;
2016-07-23 09:26:06 +02:00
else
2020-07-03 11:42:58 +02:00
alternativeOp = & XOR ;
2016-07-20 12:21:00 +02:00
for ( tok = tok1 ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
2020-07-03 11:42:58 +02:00
if ( tok - > op ! = * op & & ! isAlternativeBinaryOp ( tok , * alternativeOp ) )
2016-07-20 12:21:00 +02:00
continue ;
if ( ! tok - > previous | | ! tok - > previous - > number )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
long long result ;
2016-07-23 09:26:06 +02:00
if ( * op = = ' & ' )
2018-05-14 13:00:22 +02:00
result = ( stringToLL ( tok - > previous - > str ( ) ) & stringToLL ( tok - > next - > str ( ) ) ) ;
2016-07-23 09:26:06 +02:00
else if ( * op = = ' ^ ' )
2018-05-14 13:00:22 +02:00
result = ( stringToLL ( tok - > previous - > str ( ) ) ^ stringToLL ( tok - > next - > str ( ) ) ) ;
2016-07-23 09:26:06 +02:00
else /*if (*op == '|')*/
2018-05-14 13:00:22 +02:00
result = ( stringToLL ( tok - > previous - > str ( ) ) | stringToLL ( tok - > next - > str ( ) ) ) ;
2016-07-20 12:21:00 +02:00
tok = tok - > previous ;
2016-07-20 20:03:27 +02:00
tok - > setstr ( toString ( result ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
}
}
2016-12-06 14:10:57 +01:00
static const std : : string AND ( " and " ) ;
static const std : : string OR ( " or " ) ;
void simplecpp : : TokenList : : constFoldLogicalOp ( Token * tok )
{
2016-07-20 12:21:00 +02:00
for ( ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
2016-07-31 20:48:55 +02:00
if ( tok - > name ) {
if ( isAlternativeBinaryOp ( tok , AND ) )
tok - > setstr ( " && " ) ;
else if ( isAlternativeBinaryOp ( tok , OR ) )
tok - > setstr ( " || " ) ;
}
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) ! = " && " & & tok - > str ( ) ! = " || " )
2016-07-20 12:21:00 +02:00
continue ;
if ( ! tok - > previous | | ! tok - > previous - > number )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
int result ;
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) = = " || " )
result = ( stringToLL ( tok - > previous - > str ( ) ) | | stringToLL ( tok - > next - > str ( ) ) ) ;
else /*if (tok->str() == "&&")*/
result = ( stringToLL ( tok - > previous - > str ( ) ) & & stringToLL ( tok - > next - > str ( ) ) ) ;
2016-07-20 12:21:00 +02:00
tok = tok - > previous ;
2016-07-20 20:03:27 +02:00
tok - > setstr ( toString ( result ) ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : constFoldQuestionOp ( Token * * tok1 )
{
2016-07-20 12:21:00 +02:00
bool gotoTok1 = false ;
for ( Token * tok = * tok1 ; tok & & tok - > op ! = ' ) ' ; tok = gotoTok1 ? * tok1 : tok - > next ) {
gotoTok1 = false ;
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) ! = " ? " )
2016-07-20 12:21:00 +02:00
continue ;
2016-11-10 20:04:05 +01:00
if ( ! tok - > previous | | ! tok - > next | | ! tok - > next - > next )
throw std : : runtime_error ( " invalid expression " ) ;
if ( ! tok - > previous - > number )
2016-07-20 12:21:00 +02:00
continue ;
2016-11-10 20:04:05 +01:00
if ( tok - > next - > next - > op ! = ' : ' )
2016-07-20 12:21:00 +02:00
continue ;
Token * const condTok = tok - > previous ;
Token * const trueTok = tok - > next ;
Token * const falseTok = trueTok - > next - > next ;
2016-11-10 20:04:05 +01:00
if ( ! falseTok )
throw std : : runtime_error ( " invalid expression " ) ;
2016-07-20 12:21:00 +02:00
if ( condTok = = * tok1 )
2018-05-14 13:00:22 +02:00
* tok1 = ( condTok - > str ( ) ! = " 0 " ? trueTok : falseTok ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( condTok - > next ) ; // ?
deleteToken ( trueTok - > next ) ; // :
2018-05-14 13:00:22 +02:00
deleteToken ( condTok - > str ( ) = = " 0 " ? trueTok : falseTok ) ;
2016-07-20 12:21:00 +02:00
deleteToken ( condTok ) ;
gotoTok1 = true ;
}
}
2016-12-06 14:10:57 +01:00
void simplecpp : : TokenList : : removeComments ( )
{
2016-07-29 08:46:38 +02:00
Token * tok = frontToken ;
2016-07-20 12:21:00 +02:00
while ( tok ) {
2022-09-30 07:26:48 +02:00
Token * const tok1 = tok ;
2016-07-20 12:21:00 +02:00
tok = tok - > next ;
if ( tok1 - > comment )
deleteToken ( tok1 ) ;
}
}
2023-03-13 16:11:46 +01:00
std : : string simplecpp : : TokenList : : readUntil ( Stream & stream , const Location & location , const char start , const char end , OutputList * outputList )
2016-12-06 14:10:57 +01:00
{
2016-07-20 12:21:00 +02:00
std : : string ret ;
ret + = start ;
2017-05-28 15:23:15 +02:00
bool backslash = false ;
2016-07-20 12:21:00 +02:00
char ch = 0 ;
2023-03-13 16:11:46 +01:00
while ( ch ! = end & & ch ! = ' \r ' & & ch ! = ' \n ' & & stream . good ( ) ) {
ch = stream . readChar ( ) ;
2017-05-28 15:23:15 +02:00
if ( backslash & & ch = = ' \n ' ) {
ch = 0 ;
backslash = false ;
continue ;
}
backslash = false ;
2016-07-20 12:21:00 +02:00
ret + = ch ;
2017-05-28 15:23:15 +02:00
if ( ch = = ' \\ ' ) {
2019-10-08 10:38:22 +02:00
bool update_ch = false ;
char next = 0 ;
do {
2023-03-13 16:11:46 +01:00
next = stream . readChar ( ) ;
2019-10-08 10:38:22 +02:00
if ( next = = ' \r ' | | next = = ' \n ' ) {
2021-02-21 19:13:16 +01:00
ret . erase ( ret . size ( ) - 1U ) ;
2019-10-08 10:38:22 +02:00
backslash = ( next = = ' \r ' ) ;
update_ch = false ;
} else if ( next = = ' \\ ' )
update_ch = ! update_ch ;
ret + = next ;
} while ( next = = ' \\ ' ) ;
if ( update_ch )
ch = next ;
2017-05-28 15:23:15 +02:00
}
2016-07-20 12:21:00 +02:00
}
2023-03-13 16:11:46 +01:00
if ( ! stream . good ( ) | | ch ! = end ) {
2016-07-20 12:21:00 +02:00
clear ( ) ;
if ( outputList ) {
Output err ( files ) ;
2016-08-06 13:01:39 +02:00
err . type = Output : : SYNTAX_ERROR ;
2016-07-20 12:21:00 +02:00
err . location = location ;
err . msg = std : : string ( " No pair for character ( " ) + start + " ). Can't process file. File is either invalid or unicode, which is currently not supported. " ;
outputList - > push_back ( err ) ;
}
return " " ;
}
return ret ;
}
2016-12-06 14:10:57 +01:00
std : : string simplecpp : : TokenList : : lastLine ( int maxsize ) const
{
2016-07-20 12:21:00 +02:00
std : : string ret ;
2016-07-28 09:26:23 +02:00
int count = 0 ;
2022-03-22 21:14:48 +01:00
for ( const Token * tok = cback ( ) ; ; tok = tok - > previous ) {
if ( ! sameline ( tok , cback ( ) ) ) {
break ;
}
2016-07-20 12:21:00 +02:00
if ( tok - > comment )
continue ;
2022-03-21 18:53:18 +01:00
if ( + + count > maxsize )
2022-03-21 19:11:26 +01:00
return " " ;
2022-03-22 21:14:48 +01:00
if ( ! ret . empty ( ) )
2023-09-13 10:30:42 +02:00
ret + = ' ' ;
// add tokens in reverse for performance reasons
2022-03-22 21:14:48 +01:00
if ( tok - > str ( ) [ 0 ] = = ' \" ' )
2023-09-13 10:30:42 +02:00
ret + = " %rts% " ; // %str%
2022-03-22 21:14:48 +01:00
else if ( tok - > number )
2023-09-13 10:30:42 +02:00
ret + = " %mun% " ; // %num%
else {
ret + = tok - > str ( ) ;
std : : reverse ( ret . end ( ) - tok - > str ( ) . length ( ) , ret . end ( ) ) ;
}
2022-03-21 18:53:18 +01:00
}
2023-09-13 10:30:42 +02:00
std : : reverse ( ret . begin ( ) , ret . end ( ) ) ;
2022-03-21 19:11:26 +01:00
return ret ;
2022-03-21 18:53:18 +01:00
}
2022-03-22 21:14:48 +01:00
bool simplecpp : : TokenList : : isLastLinePreprocessor ( int maxsize ) const
{
const Token * prevTok = nullptr ;
int count = 0 ;
for ( const Token * tok = cback ( ) ; ; tok = tok - > previous ) {
if ( ! sameline ( tok , cback ( ) ) )
break ;
if ( tok - > comment )
continue ;
if ( + + count > maxsize )
return false ;
prevTok = tok ;
}
return prevTok & & prevTok - > str ( ) [ 0 ] = = ' # ' ;
}
2016-12-06 14:10:57 +01:00
unsigned int simplecpp : : TokenList : : fileIndex ( const std : : string & filename )
{
2016-07-20 12:21:00 +02:00
for ( unsigned int i = 0 ; i < files . size ( ) ; + + i ) {
if ( files [ i ] = = filename )
return i ;
}
files . push_back ( filename ) ;
return files . size ( ) - 1U ;
}
namespace simplecpp {
2022-03-22 21:14:48 +01:00
class Macro ;
# if __cplusplus >= 201103L
using MacroMap = std : : unordered_map < TokenString , Macro > ;
# else
typedef std : : map < TokenString , Macro > MacroMap ;
# endif
2016-12-06 14:10:57 +01:00
class Macro {
public :
2022-09-30 07:26:48 +02:00
explicit Macro ( std : : vector < std : : string > & f ) : nameTokDef ( nullptr ) , valueToken ( nullptr ) , endToken ( nullptr ) , files ( f ) , tokenListDefine ( f ) , variadic ( false ) , valueDefinedInCode_ ( false ) { }
2016-12-06 14:10:57 +01:00
2022-03-22 21:14:48 +01:00
Macro ( const Token * tok , std : : vector < std : : string > & f ) : nameTokDef ( nullptr ) , files ( f ) , tokenListDefine ( f ) , valueDefinedInCode_ ( true ) {
2023-04-18 20:15:24 +02:00
if ( sameline ( tok - > previousSkipComments ( ) , tok ) )
2016-12-06 14:10:57 +01:00
throw std : : runtime_error ( " bad macro syntax " ) ;
if ( tok - > op ! = ' # ' )
throw std : : runtime_error ( " bad macro syntax " ) ;
const Token * const hashtok = tok ;
tok = tok - > next ;
2018-05-14 13:00:22 +02:00
if ( ! tok | | tok - > str ( ) ! = DEFINE )
2016-12-06 14:10:57 +01:00
throw std : : runtime_error ( " bad macro syntax " ) ;
tok = tok - > next ;
if ( ! tok | | ! tok - > name | | ! sameline ( hashtok , tok ) )
throw std : : runtime_error ( " bad macro syntax " ) ;
if ( ! parseDefine ( tok ) )
throw std : : runtime_error ( " bad macro syntax " ) ;
}
2016-07-20 12:21:00 +02:00
2022-03-22 21:14:48 +01:00
Macro ( const std : : string & name , const std : : string & value , std : : vector < std : : string > & f ) : nameTokDef ( nullptr ) , files ( f ) , tokenListDefine ( f ) , valueDefinedInCode_ ( false ) {
2016-12-06 14:10:57 +01:00
const std : : string def ( name + ' ' + value ) ;
std : : istringstream istr ( def ) ;
2023-03-13 16:11:46 +01:00
StdIStream stream ( istr ) ;
tokenListDefine . readfile ( stream ) ;
2016-12-06 14:10:57 +01:00
if ( ! parseDefine ( tokenListDefine . cfront ( ) ) )
2019-02-06 16:26:59 +01:00
throw std : : runtime_error ( " bad macro syntax. macroname= " + name + " value= " + value ) ;
2016-12-06 14:10:57 +01:00
}
2016-07-20 12:21:00 +02:00
2022-03-22 21:14:48 +01:00
Macro ( const Macro & other ) : nameTokDef ( nullptr ) , files ( other . files ) , tokenListDefine ( other . files ) , valueDefinedInCode_ ( other . valueDefinedInCode_ ) {
* this = other ;
2016-12-06 14:10:57 +01:00
}
2016-07-20 12:21:00 +02:00
2022-03-22 21:14:48 +01:00
Macro & operator = ( const Macro & other ) {
if ( this ! = & other ) {
files = other . files ;
valueDefinedInCode_ = other . valueDefinedInCode_ ;
if ( other . tokenListDefine . empty ( ) )
parseDefine ( other . nameTokDef ) ;
2016-12-06 14:10:57 +01:00
else {
2022-03-22 21:14:48 +01:00
tokenListDefine = other . tokenListDefine ;
2016-12-06 14:10:57 +01:00
parseDefine ( tokenListDefine . cfront ( ) ) ;
}
2023-09-13 10:30:42 +02:00
usageList = other . usageList ;
2016-07-20 12:21:00 +02:00
}
2022-03-22 21:14:48 +01:00
return * this ;
2016-07-20 12:21:00 +02:00
}
2018-09-26 12:17:14 +02:00
bool valueDefinedInCode ( ) const {
return valueDefinedInCode_ ;
}
2016-12-06 14:10:57 +01:00
/**
* Expand macro . This will recursively expand inner macros .
2017-08-13 13:59:09 +02:00
* @ param output destination tokenlist
* @ param rawtok macro token
* @ param macros list of macros
* @ param inputFiles the input files
2016-12-06 14:10:57 +01:00
* @ return token after macro
* @ throw Can throw wrongNumberOfParameters or invalidHashHash
*/
const Token * expand ( TokenList * const output ,
const Token * rawtok ,
2022-03-22 21:14:48 +01:00
const MacroMap & macros ,
2017-08-13 13:59:09 +02:00
std : : vector < std : : string > & inputFiles ) const {
2016-12-06 14:10:57 +01:00
std : : set < TokenString > expandedmacros ;
2017-08-13 13:59:09 +02:00
TokenList output2 ( inputFiles ) ;
2016-12-06 14:10:57 +01:00
if ( functionLike ( ) & & rawtok - > next & & rawtok - > next - > op = = ' ( ' ) {
// Copy macro call to a new tokenlist with no linebreaks
const Token * const rawtok1 = rawtok ;
2017-08-13 13:59:09 +02:00
TokenList rawtokens2 ( inputFiles ) ;
2018-05-14 13:00:22 +02:00
rawtokens2 . push_back ( new Token ( rawtok - > str ( ) , rawtok1 - > location ) ) ;
2016-08-06 13:01:39 +02:00
rawtok = rawtok - > next ;
2018-05-14 13:00:22 +02:00
rawtokens2 . push_back ( new Token ( rawtok - > str ( ) , rawtok1 - > location ) ) ;
2016-12-06 14:10:57 +01:00
rawtok = rawtok - > next ;
int par = 1 ;
while ( rawtok & & par > 0 ) {
if ( rawtok - > op = = ' ( ' )
+ + par ;
else if ( rawtok - > op = = ' ) ' )
- - par ;
2018-04-17 08:12:15 +02:00
else if ( rawtok - > op = = ' # ' & & ! sameline ( rawtok - > previous , rawtok ) )
throw Error ( rawtok - > location , " it is invalid to use a preprocessor directive as macro parameter " ) ;
2018-05-14 13:00:22 +02:00
rawtokens2 . push_back ( new Token ( rawtok - > str ( ) , rawtok1 - > location ) ) ;
2016-12-06 14:10:57 +01:00
rawtok = rawtok - > next ;
2016-07-24 08:22:49 +02:00
}
2021-04-26 16:25:39 +02:00
bool first = true ;
if ( valueToken & & valueToken - > str ( ) = = rawtok1 - > str ( ) )
first = false ;
if ( expand ( & output2 , rawtok1 - > location , rawtokens2 . cfront ( ) , macros , expandedmacros , first ) )
2016-12-06 14:10:57 +01:00
rawtok = rawtok1 - > next ;
} else {
rawtok = expand ( & output2 , rawtok - > location , rawtok , macros , expandedmacros ) ;
2016-07-23 16:26:11 +02:00
}
2016-12-06 14:10:57 +01:00
while ( output2 . cback ( ) & & rawtok ) {
unsigned int par = 0 ;
Token * macro2tok = output2 . back ( ) ;
while ( macro2tok ) {
if ( macro2tok - > op = = ' ( ' ) {
if ( par = = 0 )
break ;
- - par ;
} else if ( macro2tok - > op = = ' ) ' )
+ + par ;
macro2tok = macro2tok - > previous ;
}
if ( macro2tok ) { // macro2tok->op == '('
macro2tok = macro2tok - > previous ;
expandedmacros . insert ( name ( ) ) ;
} else if ( rawtok - > op = = ' ( ' )
macro2tok = output2 . back ( ) ;
if ( ! macro2tok | | ! macro2tok - > name )
break ;
2018-05-14 13:00:22 +02:00
if ( output2 . cfront ( ) ! = output2 . cback ( ) & & macro2tok - > str ( ) = = this - > name ( ) )
2016-12-06 14:10:57 +01:00
break ;
2022-03-22 21:14:48 +01:00
const MacroMap : : const_iterator macro = macros . find ( macro2tok - > str ( ) ) ;
2016-12-06 14:10:57 +01:00
if ( macro = = macros . end ( ) | | ! macro - > second . functionLike ( ) )
break ;
2017-08-13 13:59:09 +02:00
TokenList rawtokens2 ( inputFiles ) ;
2016-12-06 14:10:57 +01:00
const Location loc ( macro2tok - > location ) ;
while ( macro2tok ) {
2022-09-30 07:26:48 +02:00
Token * const next = macro2tok - > next ;
2018-05-14 13:00:22 +02:00
rawtokens2 . push_back ( new Token ( macro2tok - > str ( ) , loc ) ) ;
2016-12-06 14:10:57 +01:00
output2 . deleteToken ( macro2tok ) ;
macro2tok = next ;
}
par = ( rawtokens2 . cfront ( ) ! = rawtokens2 . cback ( ) ) ? 1U : 0U ;
const Token * rawtok2 = rawtok ;
for ( ; rawtok2 ; rawtok2 = rawtok2 - > next ) {
2018-05-14 13:00:22 +02:00
rawtokens2 . push_back ( new Token ( rawtok2 - > str ( ) , loc ) ) ;
2016-12-06 14:10:57 +01:00
if ( rawtok2 - > op = = ' ( ' )
+ + par ;
else if ( rawtok2 - > op = = ' ) ' ) {
if ( par < = 1U )
break ;
- - par ;
}
2016-07-23 16:26:11 +02:00
}
2016-12-06 14:10:57 +01:00
if ( ! rawtok2 | | par ! = 1U )
break ;
2022-03-22 21:14:48 +01:00
if ( macro - > second . expand ( & output2 , rawtok - > location , rawtokens2 . cfront ( ) , macros , expandedmacros ) ! = nullptr )
2016-12-06 14:10:57 +01:00
break ;
rawtok = rawtok2 - > next ;
2016-07-23 16:26:11 +02:00
}
2016-12-06 14:10:57 +01:00
output - > takeTokens ( output2 ) ;
2023-10-05 18:20:42 +02:00
for ( Token * tok = output - > front ( ) ; tok ; tok = tok - > next ) {
if ( tok - > str ( ) = = INNER_COMMA )
tok - > setstr ( " , " ) ;
}
2016-12-06 14:10:57 +01:00
return rawtok ;
2016-07-23 16:26:11 +02:00
}
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
/** macro name */
const TokenString & name ( ) const {
2018-05-14 13:00:22 +02:00
return nameTokDef - > str ( ) ;
2016-12-06 14:10:57 +01:00
}
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
/** location for macro definition */
const Location & defineLocation ( ) const {
return nameTokDef - > location ;
}
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
/** how has this macro been used so far */
const std : : list < Location > & usage ( ) const {
return usageList ;
}
2016-07-23 16:26:11 +02:00
2016-12-06 14:10:57 +01:00
/** is this a function like macro */
bool functionLike ( ) const {
return nameTokDef - > next & &
nameTokDef - > next - > op = = ' ( ' & &
sameline ( nameTokDef , nameTokDef - > next ) & &
2018-05-14 13:00:22 +02:00
nameTokDef - > next - > location . col = = nameTokDef - > location . col + nameTokDef - > str ( ) . size ( ) ;
2016-12-06 14:10:57 +01:00
}
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
/** base class for errors */
struct Error {
Error ( const Location & loc , const std : : string & s ) : location ( loc ) , what ( s ) { }
2022-03-22 21:14:48 +01:00
const Location location ;
const std : : string what ;
2016-12-06 14:10:57 +01:00
} ;
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
/** Struct that is thrown when macro is expanded with wrong number of parameters */
struct wrongNumberOfParameters : public Error {
wrongNumberOfParameters ( const Location & loc , const std : : string & macroName ) : Error ( loc , " Wrong number of parameters for macro \' " + macroName + " \' . " ) { }
} ;
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
/** Struct that is thrown when there is invalid ## usage */
struct invalidHashHash : public Error {
2022-03-22 21:14:48 +01:00
static inline std : : string format ( const std : : string & macroName , const std : : string & message ) {
return " Invalid ## usage when expanding \' " + macroName + " \' : " + message ;
}
invalidHashHash ( const Location & loc , const std : : string & macroName , const std : : string & message )
: Error ( loc , format ( macroName , message ) ) { }
static inline invalidHashHash unexpectedToken ( const Location & loc , const std : : string & macroName , const Token * tokenA ) {
return invalidHashHash ( loc , macroName , " Unexpected token ' " + tokenA - > str ( ) + " ' " ) ;
}
static inline invalidHashHash cannotCombine ( const Location & loc , const std : : string & macroName , const Token * tokenA , const Token * tokenB ) {
2022-07-27 21:46:03 +02:00
return invalidHashHash ( loc , macroName , " Combining ' " + tokenA - > str ( ) + " ' and ' " + tokenB - > str ( ) + " ' yields an invalid token. " ) ;
2022-03-22 21:14:48 +01:00
}
static inline invalidHashHash unexpectedNewline ( const Location & loc , const std : : string & macroName ) {
return invalidHashHash ( loc , macroName , " Unexpected newline " ) ;
}
2022-07-27 21:46:03 +02:00
static inline invalidHashHash universalCharacterUB ( const Location & loc , const std : : string & macroName , const Token * tokenA , const std : : string & strAB ) {
return invalidHashHash ( loc , macroName , " Combining ' \\ " + tokenA - > str ( ) + " ' and ' " + strAB . substr ( tokenA - > str ( ) . size ( ) ) + " ' yields universal character ' \\ " + strAB + " '. This is undefined behavior according to C standard chapter 5.1.1.2, paragraph 4. " ) ;
}
2016-12-06 14:10:57 +01:00
} ;
private :
/** Create new token where Token::macro is set for replaced tokens */
2022-03-22 21:14:48 +01:00
Token * newMacroToken ( const TokenString & str , const Location & loc , bool replaced , const Token * expandedFromToken = nullptr ) const {
2016-12-06 14:10:57 +01:00
Token * tok = new Token ( str , loc ) ;
if ( replaced )
2018-05-14 13:00:22 +02:00
tok - > macro = nameTokDef - > str ( ) ;
2021-12-16 21:18:05 +01:00
if ( expandedFromToken )
tok - > setExpandedFrom ( expandedFromToken , this ) ;
2016-12-06 14:10:57 +01:00
return tok ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
bool parseDefine ( const Token * nametoken ) {
nameTokDef = nametoken ;
variadic = false ;
if ( ! nameTokDef ) {
2022-03-22 21:14:48 +01:00
valueToken = endToken = nullptr ;
2016-12-06 14:10:57 +01:00
args . clear ( ) ;
return false ;
}
// function like macro..
if ( functionLike ( ) ) {
args . clear ( ) ;
const Token * argtok = nameTokDef - > next - > next ;
while ( sameline ( nametoken , argtok ) & & argtok - > op ! = ' ) ' ) {
2019-09-04 08:07:30 +02:00
if ( argtok - > str ( ) = = " ... " & &
argtok - > next & & argtok - > next - > op = = ' ) ' ) {
2016-12-06 14:10:57 +01:00
variadic = true ;
if ( ! argtok - > previous - > name )
args . push_back ( " __VA_ARGS__ " ) ;
2019-09-04 08:07:30 +02:00
argtok = argtok - > next ; // goto ')'
2016-12-06 14:10:57 +01:00
break ;
}
if ( argtok - > op ! = ' , ' )
2018-05-14 13:00:22 +02:00
args . push_back ( argtok - > str ( ) ) ;
2016-12-06 14:10:57 +01:00
argtok = argtok - > next ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
if ( ! sameline ( nametoken , argtok ) ) {
2017-09-05 23:19:56 +02:00
endToken = argtok ? argtok - > previous : argtok ;
2022-03-22 21:14:48 +01:00
valueToken = nullptr ;
2016-12-06 14:10:57 +01:00
return false ;
}
2022-03-22 21:14:48 +01:00
valueToken = argtok ? argtok - > next : nullptr ;
2016-12-06 14:10:57 +01:00
} else {
args . clear ( ) ;
valueToken = nameTokDef - > next ;
2016-11-10 20:04:05 +01:00
}
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
if ( ! sameline ( valueToken , nameTokDef ) )
2022-03-22 21:14:48 +01:00
valueToken = nullptr ;
2016-12-06 14:10:57 +01:00
endToken = valueToken ;
while ( sameline ( endToken , nameTokDef ) )
endToken = endToken - > next ;
return true ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
unsigned int getArgNum ( const TokenString & str ) const {
unsigned int par = 0 ;
while ( par < args . size ( ) ) {
if ( str = = args [ par ] )
return par ;
par + + ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
return ~ 0U ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
std : : vector < const Token * > getMacroParameters ( const Token * nameTokInst , bool calledInDefine ) const {
if ( ! nameTokInst - > next | | nameTokInst - > next - > op ! = ' ( ' | | ! functionLike ( ) )
return std : : vector < const Token * > ( ) ;
2016-08-24 20:27:29 +02:00
2016-12-06 14:10:57 +01:00
std : : vector < const Token * > parametertokens ;
parametertokens . push_back ( nameTokInst - > next ) ;
unsigned int par = 0U ;
2022-03-22 21:14:48 +01:00
for ( const Token * tok = nameTokInst - > next - > next ; calledInDefine ? sameline ( tok , nameTokInst ) : ( tok ! = nullptr ) ; tok = tok - > next ) {
2016-08-04 22:53:10 +02:00
if ( tok - > op = = ' ( ' )
+ + par ;
else if ( tok - > op = = ' ) ' ) {
2016-12-06 14:10:57 +01:00
if ( par = = 0U ) {
parametertokens . push_back ( tok ) ;
2016-08-04 22:53:10 +02:00
break ;
2016-12-06 14:10:57 +01:00
}
- - par ;
} else if ( par = = 0U & & tok - > op = = ' , ' & & ( ! variadic | | parametertokens . size ( ) < args . size ( ) ) )
parametertokens . push_back ( tok ) ;
2016-07-23 09:26:06 +02:00
}
2016-12-06 14:10:57 +01:00
return parametertokens ;
2016-07-23 09:26:06 +02:00
}
2016-12-06 14:10:57 +01:00
const Token * appendTokens ( TokenList * tokens ,
2020-07-03 11:42:58 +02:00
const Location & rawloc ,
const Token * const lpar ,
2022-03-22 21:14:48 +01:00
const MacroMap & macros ,
2016-12-06 14:10:57 +01:00
const std : : set < TokenString > & expandedmacros ,
const std : : vector < const Token * > & parametertokens ) const {
if ( ! lpar | | lpar - > op ! = ' ( ' )
2022-03-22 21:14:48 +01:00
return nullptr ;
2016-12-06 14:10:57 +01:00
unsigned int par = 0 ;
const Token * tok = lpar ;
while ( sameline ( lpar , tok ) ) {
if ( tok - > op = = ' # ' & & sameline ( tok , tok - > next ) & & tok - > next - > op = = ' # ' & & sameline ( tok , tok - > next - > next ) ) {
// A##B => AB
2020-07-03 11:42:58 +02:00
tok = expandHashHash ( tokens , rawloc , tok , macros , expandedmacros , parametertokens ) ;
2016-12-06 14:10:57 +01:00
} else if ( tok - > op = = ' # ' & & sameline ( tok , tok - > next ) & & tok - > next - > op ! = ' # ' ) {
2020-07-03 11:42:58 +02:00
tok = expandHash ( tokens , rawloc , tok , macros , expandedmacros , parametertokens ) ;
2016-12-06 14:10:57 +01:00
} else {
2020-07-03 11:42:58 +02:00
if ( ! expandArg ( tokens , tok , rawloc , macros , expandedmacros , parametertokens ) ) {
2016-12-06 14:10:57 +01:00
bool expanded = false ;
2022-03-22 21:14:48 +01:00
const MacroMap : : const_iterator it = macros . find ( tok - > str ( ) ) ;
2018-05-14 13:00:22 +02:00
if ( it ! = macros . end ( ) & & expandedmacros . find ( tok - > str ( ) ) = = expandedmacros . end ( ) ) {
2016-12-06 14:10:57 +01:00
const Macro & m = it - > second ;
if ( ! m . functionLike ( ) ) {
2023-10-05 18:20:42 +02:00
Token * mtok = tokens - > back ( ) ;
2020-07-03 11:42:58 +02:00
m . expand ( tokens , rawloc , tok , macros , expandedmacros ) ;
2023-10-05 18:20:42 +02:00
for ( mtok = mtok - > next ; mtok ; mtok = mtok - > next ) {
if ( mtok - > op = = ' , ' )
mtok - > setstr ( INNER_COMMA ) ;
}
2016-12-06 14:10:57 +01:00
expanded = true ;
}
}
2021-06-28 19:47:37 +02:00
if ( ! expanded ) {
2016-12-06 14:10:57 +01:00
tokens - > push_back ( new Token ( * tok ) ) ;
2021-06-28 19:47:37 +02:00
if ( tok - > macro . empty ( ) & & ( par > 0 | | tok - > str ( ) ! = " ( " ) )
tokens - > back ( ) - > macro = name ( ) ;
}
2016-12-06 14:10:57 +01:00
}
2016-07-29 08:46:38 +02:00
2016-12-06 14:10:57 +01:00
if ( tok - > op = = ' ( ' )
+ + par ;
else if ( tok - > op = = ' ) ' ) {
- - par ;
if ( par = = 0U )
break ;
}
tok = tok - > next ;
}
}
2020-07-03 11:42:58 +02:00
for ( Token * tok2 = tokens - > front ( ) ; tok2 ; tok2 = tok2 - > next )
tok2 - > location = lpar - > location ;
2022-03-22 21:14:48 +01:00
return sameline ( lpar , tok ) ? tok : nullptr ;
2016-07-29 08:46:38 +02:00
}
2022-03-22 21:14:48 +01:00
const Token * expand ( TokenList * const output , const Location & loc , const Token * const nameTokInst , const MacroMap & macros , std : : set < TokenString > expandedmacros , bool first = false ) const {
2021-04-26 16:25:39 +02:00
if ( ! first )
expandedmacros . insert ( nameTokInst - > str ( ) ) ;
2016-07-31 12:10:30 +02:00
2016-12-06 14:10:57 +01:00
usageList . push_back ( loc ) ;
2016-07-29 08:46:38 +02:00
2018-05-14 13:00:22 +02:00
if ( nameTokInst - > str ( ) = = " __FILE__ " ) {
2016-12-06 14:10:57 +01:00
output - > push_back ( new Token ( ' \" ' + loc . file ( ) + ' \" ' , loc ) ) ;
return nameTokInst - > next ;
2016-07-29 08:46:38 +02:00
}
2018-05-14 13:00:22 +02:00
if ( nameTokInst - > str ( ) = = " __LINE__ " ) {
2016-12-06 14:10:57 +01:00
output - > push_back ( new Token ( toString ( loc . line ) , loc ) ) ;
return nameTokInst - > next ;
}
2018-05-14 13:00:22 +02:00
if ( nameTokInst - > str ( ) = = " __COUNTER__ " ) {
2016-12-06 14:10:57 +01:00
output - > push_back ( new Token ( toString ( usageList . size ( ) - 1U ) , loc ) ) ;
return nameTokInst - > next ;
}
const bool calledInDefine = ( loc . fileIndex ! = nameTokInst - > location . fileIndex | |
loc . line < nameTokInst - > location . line ) ;
2016-07-29 08:46:38 +02:00
2016-12-06 14:10:57 +01:00
std : : vector < const Token * > parametertokens1 ( getMacroParameters ( nameTokInst , calledInDefine ) ) ;
if ( functionLike ( ) ) {
// No arguments => not macro expansion
if ( nameTokInst - > next & & nameTokInst - > next - > op ! = ' ( ' ) {
2018-05-14 13:00:22 +02:00
output - > push_back ( new Token ( nameTokInst - > str ( ) , loc ) ) ;
2016-12-06 14:10:57 +01:00
return nameTokInst - > next ;
2016-07-29 08:46:38 +02:00
}
2016-12-06 14:10:57 +01:00
// Parse macro-call
if ( variadic ) {
if ( parametertokens1 . size ( ) < args . size ( ) ) {
throw wrongNumberOfParameters ( nameTokInst - > location , name ( ) ) ;
}
} else {
if ( parametertokens1 . size ( ) ! = args . size ( ) + ( args . empty ( ) ? 2U : 1U ) )
throw wrongNumberOfParameters ( nameTokInst - > location , name ( ) ) ;
2016-07-29 20:54:11 +02:00
}
}
2016-12-06 14:10:57 +01:00
// If macro call uses __COUNTER__ then expand that first
TokenList tokensparams ( files ) ;
std : : vector < const Token * > parametertokens2 ;
if ( ! parametertokens1 . empty ( ) ) {
bool counter = false ;
for ( const Token * tok = parametertokens1 [ 0 ] ; tok ! = parametertokens1 . back ( ) ; tok = tok - > next ) {
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) = = " __COUNTER__ " ) {
2016-12-06 14:10:57 +01:00
counter = true ;
break ;
}
}
2022-03-22 21:14:48 +01:00
const MacroMap : : const_iterator m = macros . find ( " __COUNTER__ " ) ;
2016-12-06 14:10:57 +01:00
if ( ! counter | | m = = macros . end ( ) )
parametertokens2 . swap ( parametertokens1 ) ;
else {
const Macro & counterMacro = m - > second ;
unsigned int par = 0 ;
for ( const Token * tok = parametertokens1 [ 0 ] ; tok & & par < parametertokens1 . size ( ) ; tok = tok - > next ) {
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) = = " __COUNTER__ " ) {
2016-12-06 14:10:57 +01:00
tokensparams . push_back ( new Token ( toString ( counterMacro . usageList . size ( ) ) , tok - > location ) ) ;
counterMacro . usageList . push_back ( tok - > location ) ;
} else {
tokensparams . push_back ( new Token ( * tok ) ) ;
if ( tok = = parametertokens1 [ par ] ) {
parametertokens2 . push_back ( tokensparams . cback ( ) ) ;
par + + ;
}
2016-07-29 20:54:11 +02:00
}
}
}
}
2016-12-06 14:10:57 +01:00
Token * const output_end_1 = output - > back ( ) ;
2016-07-29 20:54:11 +02:00
2016-12-06 14:10:57 +01:00
// expand
for ( const Token * tok = valueToken ; tok ! = endToken ; ) {
if ( tok - > op ! = ' # ' ) {
// A##B => AB
2019-02-06 16:26:59 +01:00
if ( sameline ( tok , tok - > next ) & & tok - > next & & tok - > next - > op = = ' # ' & & tok - > next - > next & & tok - > next - > next - > op = = ' # ' ) {
2016-12-06 14:10:57 +01:00
if ( ! sameline ( tok , tok - > next - > next - > next ) )
2022-03-22 21:14:48 +01:00
throw invalidHashHash : : unexpectedNewline ( tok - > location , name ( ) ) ;
2021-06-28 19:47:37 +02:00
TokenList new_output ( files ) ;
if ( ! expandArg ( & new_output , tok , parametertokens2 ) )
2021-12-16 21:18:05 +01:00
output - > push_back ( newMacroToken ( tok - > str ( ) , loc , isReplaced ( expandedmacros ) , tok ) ) ;
2021-06-28 19:47:37 +02:00
else if ( new_output . empty ( ) ) // placemarker token
output - > push_back ( newMacroToken ( " " , loc , isReplaced ( expandedmacros ) ) ) ;
else
for ( const Token * tok2 = new_output . cfront ( ) ; tok2 ; tok2 = tok2 - > next )
2021-12-16 21:18:05 +01:00
output - > push_back ( newMacroToken ( tok2 - > str ( ) , loc , isReplaced ( expandedmacros ) , tok2 ) ) ;
2016-12-06 14:10:57 +01:00
tok = tok - > next ;
} else {
tok = expandToken ( output , loc , tok , macros , expandedmacros , parametertokens2 ) ;
}
continue ;
}
int numberOfHash = 1 ;
const Token * hashToken = tok - > next ;
while ( sameline ( tok , hashToken ) & & hashToken - > op = = ' # ' ) {
hashToken = hashToken - > next ;
+ + numberOfHash ;
}
2020-07-03 11:42:58 +02:00
if ( numberOfHash = = 4 & & tok - > next - > location . col + 1 = = tok - > next - > next - > location . col ) {
2016-12-06 14:10:57 +01:00
// # ## # => ##
output - > push_back ( newMacroToken ( " ## " , loc , isReplaced ( expandedmacros ) ) ) ;
tok = hashToken ;
continue ;
}
2020-07-03 11:42:58 +02:00
if ( numberOfHash > = 2 & & tok - > location . col + 1 < tok - > next - > location . col ) {
output - > push_back ( new Token ( * tok ) ) ;
tok = tok - > next ;
continue ;
}
2016-12-06 14:10:57 +01:00
tok = tok - > next ;
if ( tok = = endToken ) {
output - > push_back ( new Token ( * tok - > previous ) ) ;
break ;
}
if ( tok - > op = = ' # ' ) {
// A##B => AB
tok = expandHashHash ( output , loc , tok - > previous , macros , expandedmacros , parametertokens2 ) ;
2016-07-29 08:46:38 +02:00
} else {
2016-12-06 14:10:57 +01:00
// #123 => "123"
tok = expandHash ( output , loc , tok - > previous , macros , expandedmacros , parametertokens2 ) ;
2016-07-29 08:46:38 +02:00
}
}
2016-12-06 14:10:57 +01:00
if ( ! functionLike ( ) ) {
for ( Token * tok = output_end_1 ? output_end_1 - > next : output - > front ( ) ; tok ; tok = tok - > next ) {
2018-05-14 13:00:22 +02:00
tok - > macro = nameTokInst - > str ( ) ;
2016-12-06 14:10:57 +01:00
}
2016-08-31 11:25:03 +02:00
}
2016-12-06 14:10:57 +01:00
if ( ! parametertokens1 . empty ( ) )
parametertokens1 . swap ( parametertokens2 ) ;
return functionLike ( ) ? parametertokens2 . back ( ) - > next : nameTokInst - > next ;
2016-07-29 08:46:38 +02:00
}
2022-03-22 21:14:48 +01:00
const Token * recursiveExpandToken ( TokenList * output , TokenList & temp , const Location & loc , const Token * tok , const MacroMap & macros , const std : : set < TokenString > & expandedmacros , const std : : vector < const Token * > & parametertokens ) const {
2020-07-03 11:42:58 +02:00
if ( ! ( temp . cback ( ) & & temp . cback ( ) - > name & & tok - > next & & tok - > next - > op = = ' ( ' ) ) {
output - > takeTokens ( temp ) ;
return tok - > next ;
}
if ( ! sameline ( tok , tok - > next ) ) {
output - > takeTokens ( temp ) ;
return tok - > next ;
}
2022-03-22 21:14:48 +01:00
const MacroMap : : const_iterator it = macros . find ( temp . cback ( ) - > str ( ) ) ;
2020-07-03 11:42:58 +02:00
if ( it = = macros . end ( ) | | expandedmacros . find ( temp . cback ( ) - > str ( ) ) ! = expandedmacros . end ( ) ) {
output - > takeTokens ( temp ) ;
return tok - > next ;
}
const Macro & calledMacro = it - > second ;
if ( ! calledMacro . functionLike ( ) ) {
output - > takeTokens ( temp ) ;
return tok - > next ;
}
TokenList temp2 ( files ) ;
temp2 . push_back ( new Token ( temp . cback ( ) - > str ( ) , tok - > location ) ) ;
2022-09-30 07:26:48 +02:00
const Token * const tok2 = appendTokens ( & temp2 , loc , tok - > next , macros , expandedmacros , parametertokens ) ;
2020-07-03 11:42:58 +02:00
if ( ! tok2 )
return tok - > next ;
output - > takeTokens ( temp ) ;
output - > deleteToken ( output - > back ( ) ) ;
calledMacro . expand ( output , loc , temp2 . cfront ( ) , macros , expandedmacros ) ;
return tok2 - > next ;
}
2022-03-22 21:14:48 +01:00
const Token * expandToken ( TokenList * output , const Location & loc , const Token * tok , const MacroMap & macros , const std : : set < TokenString > & expandedmacros , const std : : vector < const Token * > & parametertokens ) const {
2016-12-06 14:10:57 +01:00
// Not name..
if ( ! tok - > name ) {
2021-12-16 21:18:05 +01:00
output - > push_back ( newMacroToken ( tok - > str ( ) , loc , true , tok ) ) ;
2016-12-06 14:10:57 +01:00
return tok - > next ;
2016-08-06 08:41:19 +02:00
}
2016-07-29 08:46:38 +02:00
2016-12-06 14:10:57 +01:00
// Macro parameter..
{
TokenList temp ( files ) ;
2023-06-02 17:52:13 +02:00
if ( expandArg ( & temp , tok , loc , macros , expandedmacros , parametertokens ) ) {
if ( tok - > str ( ) = = " __VA_ARGS__ " & & temp . empty ( ) & & output - > cback ( ) & & output - > cback ( ) - > str ( ) = = " , " & &
tok - > nextSkipComments ( ) & & tok - > nextSkipComments ( ) - > str ( ) = = " ) " )
output - > deleteToken ( output - > back ( ) ) ;
2020-07-03 11:42:58 +02:00
return recursiveExpandToken ( output , temp , loc , tok , macros , expandedmacros , parametertokens ) ;
2023-06-02 17:52:13 +02:00
}
2016-12-06 14:10:57 +01:00
}
2016-07-23 09:26:06 +02:00
2016-12-06 14:10:57 +01:00
// Macro..
2022-03-22 21:14:48 +01:00
const MacroMap : : const_iterator it = macros . find ( tok - > str ( ) ) ;
2018-05-14 13:00:22 +02:00
if ( it ! = macros . end ( ) & & expandedmacros . find ( tok - > str ( ) ) = = expandedmacros . end ( ) ) {
2020-07-03 11:42:58 +02:00
std : : set < std : : string > expandedmacros2 ( expandedmacros ) ;
expandedmacros2 . insert ( tok - > str ( ) ) ;
2016-07-23 09:26:06 +02:00
const Macro & calledMacro = it - > second ;
2020-07-03 11:42:58 +02:00
if ( ! calledMacro . functionLike ( ) ) {
TokenList temp ( files ) ;
calledMacro . expand ( & temp , loc , tok , macros , expandedmacros ) ;
return recursiveExpandToken ( output , temp , loc , tok , macros , expandedmacros2 , parametertokens ) ;
}
2016-12-06 14:10:57 +01:00
if ( ! sameline ( tok , tok - > next ) | | tok - > next - > op ! = ' ( ' ) {
2021-12-16 21:18:05 +01:00
output - > push_back ( newMacroToken ( tok - > str ( ) , loc , true , tok ) ) ;
2016-07-23 09:26:06 +02:00
return tok - > next ;
}
2016-12-06 14:10:57 +01:00
TokenList tokens ( files ) ;
tokens . push_back ( new Token ( * tok ) ) ;
2022-09-30 07:26:48 +02:00
const Token * const tok2 = appendTokens ( & tokens , loc , tok - > next , macros , expandedmacros , parametertokens ) ;
2016-12-06 14:10:57 +01:00
if ( ! tok2 ) {
2021-12-16 21:18:05 +01:00
output - > push_back ( newMacroToken ( tok - > str ( ) , loc , true , tok ) ) ;
2016-07-23 09:26:06 +02:00
return tok - > next ;
2016-12-06 14:10:57 +01:00
}
2020-07-03 11:42:58 +02:00
TokenList temp ( files ) ;
calledMacro . expand ( & temp , loc , tokens . cfront ( ) , macros , expandedmacros ) ;
return recursiveExpandToken ( output , temp , loc , tok2 , macros , expandedmacros2 , parametertokens ) ;
2016-07-23 09:26:06 +02:00
}
2016-07-20 12:21:00 +02:00
2022-09-30 07:26:48 +02:00
if ( tok - > str ( ) = = DEFINED ) {
const Token * const tok2 = tok - > next ;
const Token * const tok3 = tok2 ? tok2 - > next : nullptr ;
const Token * const tok4 = tok3 ? tok3 - > next : nullptr ;
2022-03-22 21:14:48 +01:00
const Token * defToken = nullptr ;
const Token * lastToken = nullptr ;
2017-06-08 15:55:12 +02:00
if ( sameline ( tok , tok4 ) & & tok2 - > op = = ' ( ' & & tok3 - > name & & tok4 - > op = = ' ) ' ) {
defToken = tok3 ;
lastToken = tok4 ;
} else if ( sameline ( tok , tok2 ) & & tok2 - > name ) {
defToken = lastToken = tok2 ;
}
if ( defToken ) {
2021-02-21 19:13:16 +01:00
std : : string macroName = defToken - > str ( ) ;
if ( defToken - > next & & defToken - > next - > op = = ' # ' & & defToken - > next - > next & & defToken - > next - > next - > op = = ' # ' & & defToken - > next - > next - > next & & defToken - > next - > next - > next - > name & & sameline ( defToken , defToken - > next - > next - > next ) ) {
TokenList temp ( files ) ;
if ( expandArg ( & temp , defToken , parametertokens ) )
macroName = temp . cback ( ) - > str ( ) ;
if ( expandArg ( & temp , defToken - > next - > next - > next , parametertokens ) )
macroName + = temp . cback ( ) - > str ( ) ;
else
macroName + = defToken - > next - > next - > next - > str ( ) ;
lastToken = defToken - > next - > next - > next ;
}
const bool def = ( macros . find ( macroName ) ! = macros . end ( ) ) ;
2017-06-08 15:55:12 +02:00
output - > push_back ( newMacroToken ( def ? " 1 " : " 0 " , loc , true ) ) ;
return lastToken - > next ;
}
}
2021-12-16 21:18:05 +01:00
output - > push_back ( newMacroToken ( tok - > str ( ) , loc , true , tok ) ) ;
2016-12-06 14:10:57 +01:00
return tok - > next ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
bool expandArg ( TokenList * output , const Token * tok , const std : : vector < const Token * > & parametertokens ) const {
if ( ! tok - > name )
return false ;
2016-07-20 12:21:00 +02:00
2018-05-14 13:00:22 +02:00
const unsigned int argnr = getArgNum ( tok - > str ( ) ) ;
2016-12-06 14:10:57 +01:00
if ( argnr > = args . size ( ) )
return false ;
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
// empty variadic parameter
if ( variadic & & argnr + 1U > = parametertokens . size ( ) )
return true ;
2016-07-24 08:51:35 +02:00
2016-12-06 14:10:57 +01:00
for ( const Token * partok = parametertokens [ argnr ] - > next ; partok ! = parametertokens [ argnr + 1U ] ; partok = partok - > next )
output - > push_back ( new Token ( * partok ) ) ;
2016-07-20 12:21:00 +02:00
2016-07-24 08:51:35 +02:00
return true ;
2016-07-20 12:21:00 +02:00
}
2022-03-22 21:14:48 +01:00
bool expandArg ( TokenList * output , const Token * tok , const Location & loc , const MacroMap & macros , const std : : set < TokenString > & expandedmacros , const std : : vector < const Token * > & parametertokens ) const {
2016-12-06 14:10:57 +01:00
if ( ! tok - > name )
return false ;
2018-05-14 13:00:22 +02:00
const unsigned int argnr = getArgNum ( tok - > str ( ) ) ;
2016-12-06 14:10:57 +01:00
if ( argnr > = args . size ( ) )
return false ;
if ( variadic & & argnr + 1U > = parametertokens . size ( ) ) // empty variadic parameter
return true ;
for ( const Token * partok = parametertokens [ argnr ] - > next ; partok ! = parametertokens [ argnr + 1U ] ; ) {
2022-03-22 21:14:48 +01:00
const MacroMap : : const_iterator it = macros . find ( partok - > str ( ) ) ;
2021-12-16 21:18:05 +01:00
if ( it ! = macros . end ( ) & & ! partok - > isExpandedFrom ( & it - > second ) & & ( partok - > str ( ) = = name ( ) | | expandedmacros . find ( partok - > str ( ) ) = = expandedmacros . end ( ) ) )
2016-12-06 14:10:57 +01:00
partok = it - > second . expand ( output , loc , partok , macros , expandedmacros ) ;
else {
2021-12-16 21:18:05 +01:00
output - > push_back ( newMacroToken ( partok - > str ( ) , loc , isReplaced ( expandedmacros ) , partok ) ) ;
2021-06-28 19:47:37 +02:00
output - > back ( ) - > macro = partok - > macro ;
2016-12-06 14:10:57 +01:00
partok = partok - > next ;
}
}
return true ;
2016-07-20 12:21:00 +02:00
}
2016-12-06 14:10:57 +01:00
/**
* Expand # X = > " X "
* @ param output destination tokenlist
* @ param loc location for expanded token
* @ param tok The # token
* @ param macros all macros
* @ param expandedmacros set with expanded macros , with this macro
* @ param parametertokens parameters given when expanding this macro
* @ return token after the X
*/
2022-03-22 21:14:48 +01:00
const Token * expandHash ( TokenList * output , const Location & loc , const Token * tok , const MacroMap & macros , const std : : set < TokenString > & expandedmacros , const std : : vector < const Token * > & parametertokens ) const {
2016-12-06 14:10:57 +01:00
TokenList tokenListHash ( files ) ;
tok = expandToken ( & tokenListHash , loc , tok - > next , macros , expandedmacros , parametertokens ) ;
std : : ostringstream ostr ;
ostr < < ' \" ' ;
for ( const Token * hashtok = tokenListHash . cfront ( ) ; hashtok ; hashtok = hashtok - > next )
2018-05-14 13:00:22 +02:00
ostr < < hashtok - > str ( ) ;
2016-12-06 14:10:57 +01:00
ostr < < ' \" ' ;
output - > push_back ( newMacroToken ( escapeString ( ostr . str ( ) ) , loc , isReplaced ( expandedmacros ) ) ) ;
return tok ;
}
/**
* Expand A # # B = > AB
* The A should already be expanded . Call this when you reach the first # token
* @ param output destination tokenlist
* @ param loc location for expanded token
* @ param tok first # token
* @ param macros all macros
* @ param expandedmacros set with expanded macros , with this macro
* @ param parametertokens parameters given when expanding this macro
* @ return token after B
*/
2022-03-22 21:14:48 +01:00
const Token * expandHashHash ( TokenList * output , const Location & loc , const Token * tok , const MacroMap & macros , const std : : set < TokenString > & expandedmacros , const std : : vector < const Token * > & parametertokens ) const {
2016-12-06 14:10:57 +01:00
Token * A = output - > back ( ) ;
if ( ! A )
2022-03-22 21:14:48 +01:00
throw invalidHashHash ( tok - > location , name ( ) , " Missing first argument " ) ;
2016-12-06 14:10:57 +01:00
if ( ! sameline ( tok , tok - > next ) | | ! sameline ( tok , tok - > next - > next ) )
2022-03-22 21:14:48 +01:00
throw invalidHashHash : : unexpectedNewline ( tok - > location , name ( ) ) ;
2019-02-23 08:35:10 +01:00
2022-09-30 07:26:48 +02:00
const bool canBeConcatenatedWithEqual = A - > isOneOf ( " +-*/%&|^ " ) | | A - > str ( ) = = " << " | | A - > str ( ) = = " >> " ;
const bool canBeConcatenatedStringOrChar = isStringLiteral_ ( A - > str ( ) ) | | isCharLiteral_ ( A - > str ( ) ) ;
2022-03-22 21:14:48 +01:00
if ( ! A - > name & & ! A - > number & & A - > op ! = ' , ' & & ! A - > str ( ) . empty ( ) & & ! canBeConcatenatedWithEqual & & ! canBeConcatenatedStringOrChar )
throw invalidHashHash : : unexpectedToken ( tok - > location , name ( ) , A ) ;
2016-12-06 14:10:57 +01:00
2022-09-30 07:26:48 +02:00
Token * const B = tok - > next - > next ;
2019-02-23 08:35:10 +01:00
if ( ! B - > name & & ! B - > number & & B - > op & & ! B - > isOneOf ( " #= " ) )
2022-03-22 21:14:48 +01:00
throw invalidHashHash : : unexpectedToken ( tok - > location , name ( ) , B ) ;
2019-02-23 08:35:10 +01:00
if ( ( canBeConcatenatedWithEqual & & B - > op ! = ' = ' ) | |
( ! canBeConcatenatedWithEqual & & B - > op = = ' = ' ) )
2022-03-22 21:14:48 +01:00
throw invalidHashHash : : cannotCombine ( tok - > location , name ( ) , A , B ) ;
2016-12-06 14:10:57 +01:00
2022-03-22 21:14:48 +01:00
// Superficial check; more in-depth would in theory be possible _after_ expandArg
if ( canBeConcatenatedStringOrChar & & ( B - > number | | ! B - > name ) )
throw invalidHashHash : : cannotCombine ( tok - > location , name ( ) , A , B ) ;
2022-03-21 18:53:18 +01:00
2022-03-21 19:11:26 +01:00
TokenList tokensB ( files ) ;
2022-03-22 21:14:48 +01:00
const Token * nextTok = B - > next ;
if ( canBeConcatenatedStringOrChar ) {
// It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here.
// TODO The question is whether the ## or varargs may still apply, and how to provoke?
if ( expandArg ( & tokensB , B , parametertokens ) ) {
for ( Token * b = tokensB . front ( ) ; b ; b = b - > next )
b - > location = loc ;
2016-12-06 14:10:57 +01:00
} else {
2022-03-22 21:14:48 +01:00
tokensB . push_back ( new Token ( * B ) ) ;
tokensB . back ( ) - > location = loc ;
2016-12-06 14:10:57 +01:00
}
2022-03-21 19:11:26 +01:00
output - > takeTokens ( tokensB ) ;
} else {
2022-03-22 21:14:48 +01:00
std : : string strAB ;
2022-09-30 07:26:48 +02:00
const bool varargs = variadic & & ! args . empty ( ) & & B - > str ( ) = = args [ args . size ( ) - 1U ] ;
2022-03-22 21:14:48 +01:00
if ( expandArg ( & tokensB , B , parametertokens ) ) {
if ( tokensB . empty ( ) )
strAB = A - > str ( ) ;
else if ( varargs & & A - > op = = ' , ' ) {
strAB = " , " ;
} else {
strAB = A - > str ( ) + tokensB . cfront ( ) - > str ( ) ;
tokensB . deleteToken ( tokensB . front ( ) ) ;
2022-03-21 18:53:18 +01:00
}
2022-03-22 21:14:48 +01:00
} else {
strAB = A - > str ( ) + B - > str ( ) ;
}
2022-07-27 21:46:03 +02:00
// producing universal character is undefined behavior
if ( A - > previous & & A - > previous - > str ( ) = = " \\ " ) {
if ( strAB [ 0 ] = = ' u ' & & strAB . size ( ) = = 5 )
throw invalidHashHash : : universalCharacterUB ( tok - > location , name ( ) , A , strAB ) ;
2022-09-30 07:26:48 +02:00
if ( strAB [ 0 ] = = ' U ' & & strAB . size ( ) = = 9 )
2022-07-27 21:46:03 +02:00
throw invalidHashHash : : universalCharacterUB ( tok - > location , name ( ) , A , strAB ) ;
}
2022-03-22 21:14:48 +01:00
if ( varargs & & tokensB . empty ( ) & & tok - > previous - > str ( ) = = " , " )
output - > deleteToken ( A ) ;
else if ( strAB ! = " , " & & macros . find ( strAB ) = = macros . end ( ) ) {
A - > setstr ( strAB ) ;
for ( Token * b = tokensB . front ( ) ; b ; b = b - > next )
b - > location = loc ;
output - > takeTokens ( tokensB ) ;
2023-03-13 16:11:46 +01:00
} else if ( sameline ( B , nextTok ) & & sameline ( B , nextTok - > next ) & & nextTok - > op = = ' # ' & & nextTok - > next - > op = = ' # ' ) {
2022-03-22 21:14:48 +01:00
TokenList output2 ( files ) ;
output2 . push_back ( new Token ( strAB , tok - > location ) ) ;
nextTok = expandHashHash ( & output2 , loc , nextTok , macros , expandedmacros , parametertokens ) ;
output - > deleteToken ( A ) ;
output - > takeTokens ( output2 ) ;
} else {
output - > deleteToken ( A ) ;
TokenList tokens ( files ) ;
tokens . push_back ( new Token ( strAB , tok - > location ) ) ;
// for function like macros, push the (...)
if ( tokensB . empty ( ) & & sameline ( B , B - > next ) & & B - > next - > op = = ' ( ' ) {
const MacroMap : : const_iterator it = macros . find ( strAB ) ;
if ( it ! = macros . end ( ) & & expandedmacros . find ( strAB ) = = expandedmacros . end ( ) & & it - > second . functionLike ( ) ) {
2022-09-30 07:26:48 +02:00
const Token * const tok2 = appendTokens ( & tokens , loc , B - > next , macros , expandedmacros , parametertokens ) ;
2022-03-22 21:14:48 +01:00
if ( tok2 )
nextTok = tok2 - > next ;
}
}
expandToken ( output , loc , tokens . cfront ( ) , macros , expandedmacros , parametertokens ) ;
for ( Token * b = tokensB . front ( ) ; b ; b = b - > next )
b - > location = loc ;
output - > takeTokens ( tokensB ) ;
2016-08-31 11:25:03 +02:00
}
}
2016-08-06 08:41:19 +02:00
2016-12-06 14:10:57 +01:00
return nextTok ;
}
2016-08-06 08:41:19 +02:00
2017-08-13 13:59:09 +02:00
static bool isReplaced ( const std : : set < std : : string > & expandedmacros ) {
2016-12-06 14:10:57 +01:00
// return true if size > 1
std : : set < std : : string > : : const_iterator it = expandedmacros . begin ( ) ;
if ( it = = expandedmacros . end ( ) )
return false ;
+ + it ;
return ( it ! = expandedmacros . end ( ) ) ;
}
2016-07-20 12:21:00 +02:00
2016-12-06 14:10:57 +01:00
/** name token in definition */
const Token * nameTokDef ;
2016-08-06 08:41:19 +02:00
2016-12-06 14:10:57 +01:00
/** arguments for macro */
std : : vector < TokenString > args ;
2016-08-06 08:41:19 +02:00
2016-12-06 14:10:57 +01:00
/** first token in replacement string */
const Token * valueToken ;
2016-08-06 08:41:19 +02:00
2016-12-06 14:10:57 +01:00
/** token after replacement string */
const Token * endToken ;
2016-08-06 08:41:19 +02:00
2016-12-06 14:10:57 +01:00
/** files */
std : : vector < std : : string > & files ;
2016-08-06 08:41:19 +02:00
2016-12-06 14:10:57 +01:00
/** this is used for -D where the definition is not seen anywhere in code */
TokenList tokenListDefine ;
2016-08-06 08:41:19 +02:00
2016-12-06 14:10:57 +01:00
/** usage of this macro */
mutable std : : list < Location > usageList ;
2018-09-26 12:17:14 +02:00
2022-09-30 07:26:48 +02:00
/** is macro variadic? */
bool variadic ;
2018-09-26 12:17:14 +02:00
/** was the value of this macro actually defined in the code? */
bool valueDefinedInCode_ ;
2016-12-06 14:10:57 +01:00
} ;
2016-07-20 12:21:00 +02:00
}
2019-03-10 08:47:27 +01:00
namespace simplecpp {
2023-09-13 10:30:42 +02:00
# ifdef __CYGWIN__
bool startsWith ( const std : : string & str , const std : : string & s )
{
return ( str . size ( ) > = s . size ( ) & & str . compare ( 0 , s . size ( ) , s ) = = 0 ) ;
}
2019-03-10 08:47:27 +01:00
std : : string convertCygwinToWindowsPath ( const std : : string & cygwinPath )
{
std : : string windowsPath ;
std : : string : : size_type pos = 0 ;
if ( cygwinPath . size ( ) > = 11 & & startsWith ( cygwinPath , " /cygdrive/ " ) ) {
2022-09-30 07:26:48 +02:00
const unsigned char driveLetter = cygwinPath [ 10 ] ;
2019-03-10 08:47:27 +01:00
if ( std : : isalpha ( driveLetter ) ) {
if ( cygwinPath . size ( ) = = 11 ) {
windowsPath = toupper ( driveLetter ) ;
windowsPath + = " : \\ " ; // volume root directory
pos = 11 ;
} else if ( cygwinPath [ 11 ] = = ' / ' ) {
windowsPath = toupper ( driveLetter ) ;
windowsPath + = " : " ;
pos = 11 ;
}
}
}
for ( ; pos < cygwinPath . size ( ) ; + + pos ) {
unsigned char c = cygwinPath [ pos ] ;
if ( c = = ' / ' )
c = ' \\ ' ;
windowsPath + = c ;
}
return windowsPath ;
}
2023-09-13 10:30:42 +02:00
# endif
2019-03-10 08:47:27 +01:00
}
2016-08-21 17:08:40 +02:00
# ifdef SIMPLECPP_WINDOWS
2019-02-06 16:26:59 +01:00
2023-09-13 10:30:42 +02:00
# if __cplusplus >= 201103L
using MyMutex = std : : mutex ;
template < class T >
using MyLock = std : : lock_guard < T > ;
# else
class MyMutex {
2019-02-06 16:26:59 +01:00
public :
2023-09-13 10:30:42 +02:00
MyMutex ( ) {
InitializeCriticalSection ( & m_criticalSection ) ;
2019-02-06 16:26:59 +01:00
}
2023-09-13 10:30:42 +02:00
~ MyMutex ( ) {
DeleteCriticalSection ( & m_criticalSection ) ;
2019-02-06 16:26:59 +01:00
}
2023-09-13 10:30:42 +02:00
CRITICAL_SECTION * lock ( ) {
return & m_criticalSection ;
}
2019-02-06 16:26:59 +01:00
private :
2023-09-13 10:30:42 +02:00
CRITICAL_SECTION m_criticalSection ;
2019-02-06 16:26:59 +01:00
} ;
2023-09-13 10:30:42 +02:00
template < typename T >
class MyLock {
2019-02-06 16:26:59 +01:00
public :
2023-09-13 10:30:42 +02:00
explicit MyLock ( T & m )
: m_mutex ( m ) {
EnterCriticalSection ( m_mutex . lock ( ) ) ;
2019-02-06 16:26:59 +01:00
}
2023-09-13 10:30:42 +02:00
~ MyLock ( ) {
LeaveCriticalSection ( m_mutex . lock ( ) ) ;
2019-02-06 16:26:59 +01:00
}
2023-09-13 10:30:42 +02:00
private :
MyLock & operator = ( const MyLock & ) ;
MyLock ( const MyLock & ) ;
T & m_mutex ;
} ;
# endif
class RealFileNameMap {
public :
RealFileNameMap ( ) { }
bool getCacheEntry ( const std : : string & path , std : : string & returnPath ) {
MyLock < MyMutex > lock ( m_mutex ) ;
2019-02-06 16:26:59 +01:00
2023-09-13 10:30:42 +02:00
const std : : map < std : : string , std : : string > : : iterator it = m_fileMap . find ( path ) ;
2019-02-23 08:35:10 +01:00
if ( it ! = m_fileMap . end ( ) ) {
2023-09-13 10:30:42 +02:00
returnPath = it - > second ;
2019-02-06 16:26:59 +01:00
return true ;
}
return false ;
}
2019-02-23 08:35:10 +01:00
void addToCache ( const std : : string & path , const std : : string & actualPath ) {
2023-09-13 10:30:42 +02:00
MyLock < MyMutex > lock ( m_mutex ) ;
2019-02-06 16:26:59 +01:00
m_fileMap [ path ] = actualPath ;
}
2019-02-23 08:35:10 +01:00
private :
2019-02-06 16:26:59 +01:00
std : : map < std : : string , std : : string > m_fileMap ;
2023-09-13 10:30:42 +02:00
MyMutex m_mutex ;
2019-02-06 16:26:59 +01:00
} ;
static RealFileNameMap realFileNameMap ;
2023-09-13 10:30:42 +02:00
static bool realFileName ( const std : : string & f , std : : string & result )
2017-06-23 20:09:26 +02:00
{
// are there alpha characters in last subpath?
bool alpha = false ;
2019-03-10 08:47:27 +01:00
for ( std : : string : : size_type pos = 1 ; pos < = f . size ( ) ; + + pos ) {
2023-09-13 10:30:42 +02:00
const unsigned char c = f [ f . size ( ) - pos ] ;
2019-03-10 08:47:27 +01:00
if ( c = = ' / ' | | c = = ' \\ ' )
2017-06-23 20:09:26 +02:00
break ;
if ( std : : isalpha ( c ) ) {
alpha = true ;
break ;
2017-06-21 12:09:50 +02:00
}
2016-11-06 12:29:13 +01:00
}
2016-09-11 20:27:57 +02:00
2017-06-23 20:09:26 +02:00
// do not convert this path if there are no alpha characters (either pointless or cause wrong results for . and ..)
if ( ! alpha )
return false ;
2017-06-21 12:09:50 +02:00
2017-06-23 20:09:26 +02:00
// Lookup filename or foldername on file system
2019-03-10 08:47:27 +01:00
if ( ! realFileNameMap . getCacheEntry ( f , result ) ) {
2019-02-06 16:26:59 +01:00
WIN32_FIND_DATAA FindFileData ;
2019-03-10 08:47:27 +01:00
# ifdef __CYGWIN__
2023-09-13 10:30:42 +02:00
const std : : string fConverted = simplecpp : : convertCygwinToWindowsPath ( f ) ;
const HANDLE hFind = FindFirstFileExA ( fConverted . c_str ( ) , FindExInfoBasic , & FindFileData , FindExSearchNameMatch , NULL , 0 ) ;
2019-03-10 08:47:27 +01:00
# else
2019-02-06 16:26:59 +01:00
HANDLE hFind = FindFirstFileExA ( f . c_str ( ) , FindExInfoBasic , & FindFileData , FindExSearchNameMatch , NULL , 0 ) ;
2019-03-10 08:47:27 +01:00
# endif
2019-02-06 16:26:59 +01:00
if ( INVALID_HANDLE_VALUE = = hFind )
return false ;
2023-09-13 10:30:42 +02:00
result = FindFileData . cFileName ;
realFileNameMap . addToCache ( f , result ) ;
2019-02-06 16:26:59 +01:00
FindClose ( hFind ) ;
}
2017-06-23 20:09:26 +02:00
return true ;
}
2017-06-21 12:09:50 +02:00
2019-03-10 08:47:27 +01:00
static RealFileNameMap realFilePathMap ;
2017-06-23 20:09:26 +02:00
/** Change case in given path to match filesystem */
static std : : string realFilename ( const std : : string & f )
{
std : : string ret ;
ret . reserve ( f . size ( ) ) ; // this will be the final size
2023-09-13 10:30:42 +02:00
if ( realFilePathMap . getCacheEntry ( f , ret ) )
2019-02-23 08:35:10 +01:00
return ret ;
2017-06-21 12:09:50 +02:00
2017-06-23 20:09:26 +02:00
// Current subpath
std : : string subpath ;
2017-06-21 12:09:50 +02:00
2017-06-23 20:09:26 +02:00
for ( std : : string : : size_type pos = 0 ; pos < f . size ( ) ; + + pos ) {
2023-09-13 10:30:42 +02:00
const unsigned char c = f [ pos ] ;
2017-06-21 12:09:50 +02:00
2017-06-23 20:09:26 +02:00
// Separator.. add subpath and separator
if ( c = = ' / ' | | c = = ' \\ ' ) {
// if subpath is empty just add separator
if ( subpath . empty ( ) ) {
2017-06-21 12:09:50 +02:00
ret + = c ;
2017-06-23 20:09:26 +02:00
continue ;
2017-05-26 16:45:07 +02:00
}
2017-06-21 12:09:50 +02:00
2023-09-13 10:30:42 +02:00
const bool isDriveSpecification =
2019-03-10 08:47:27 +01:00
( pos = = 2 & & subpath . size ( ) = = 2 & & std : : isalpha ( subpath [ 0 ] ) & & subpath [ 1 ] = = ' : ' ) ;
2017-06-23 20:09:26 +02:00
// Append real filename (proper case)
2017-06-21 12:09:50 +02:00
std : : string f2 ;
2023-09-13 10:30:42 +02:00
if ( ! isDriveSpecification & & realFileName ( f . substr ( 0 , pos ) , f2 ) )
2017-06-21 12:09:50 +02:00
ret + = f2 ;
else
ret + = subpath ;
2017-06-23 20:09:26 +02:00
subpath . clear ( ) ;
// Append separator
ret + = c ;
} else {
subpath + = c ;
}
2017-06-21 12:09:50 +02:00
}
2017-06-23 20:09:26 +02:00
if ( ! subpath . empty ( ) ) {
std : : string f2 ;
2023-09-13 10:30:42 +02:00
if ( realFileName ( f , f2 ) )
2017-06-23 20:09:26 +02:00
ret + = f2 ;
else
ret + = subpath ;
2016-08-21 17:08:40 +02:00
}
2017-06-21 12:09:50 +02:00
2019-03-10 08:47:27 +01:00
realFilePathMap . addToCache ( f , ret ) ;
2017-06-23 20:09:26 +02:00
return ret ;
}
static bool isAbsolutePath ( const std : : string & path )
{
if ( path . length ( ) > = 3 & & path [ 0 ] > 0 & & std : : isalpha ( path [ 0 ] ) & & path [ 1 ] = = ' : ' & & ( path [ 2 ] = = ' \\ ' | | path [ 2 ] = = ' / ' ) )
return true ;
2017-08-13 13:59:09 +02:00
return path . length ( ) > 1U & & ( path [ 0 ] = = ' / ' | | path [ 0 ] = = ' \\ ' ) ;
2017-06-23 20:09:26 +02:00
}
2016-08-21 17:08:40 +02:00
# else
# define realFilename(f) f
2017-06-21 12:09:50 +02:00
2017-06-23 20:09:26 +02:00
static bool isAbsolutePath ( const std : : string & path )
{
return path . length ( ) > 1U & & path [ 0 ] = = ' / ' ;
}
2016-08-17 21:16:29 +02:00
# endif
2017-06-23 20:09:26 +02:00
namespace simplecpp {
2016-12-06 14:10:57 +01:00
/**
* perform path simplifications for . and . .
*/
std : : string simplifyPath ( std : : string path )
{
2018-01-13 18:08:23 +01:00
if ( path . empty ( ) )
return path ;
2016-12-06 14:10:57 +01:00
std : : string : : size_type pos ;
2016-07-25 09:13:59 +02:00
2016-12-06 14:10:57 +01:00
// replace backslash separators
std : : replace ( path . begin ( ) , path . end ( ) , ' \\ ' , ' / ' ) ;
2016-07-24 09:59:57 +02:00
2017-06-21 12:09:50 +02:00
const bool unc ( path . compare ( 0 , 2 , " // " ) = = 0 ) ;
// replace "//" with "/"
pos = 0 ;
while ( ( pos = path . find ( " // " , pos ) ) ! = std : : string : : npos ) {
path . erase ( pos , 1 ) ;
}
2017-06-08 15:55:12 +02:00
// remove "./"
2016-12-06 14:10:57 +01:00
pos = 0 ;
2017-06-08 15:55:12 +02:00
while ( ( pos = path . find ( " ./ " , pos ) ) ! = std : : string : : npos ) {
if ( pos = = 0 | | path [ pos - 1U ] = = ' / ' )
path . erase ( pos , 2 ) ;
else
pos + = 2 ;
2016-12-06 14:10:57 +01:00
}
2016-07-24 09:59:57 +02:00
2017-06-21 12:09:50 +02:00
// remove trailing dot if path ends with "/."
if ( endsWith ( path , " /. " ) )
2021-02-21 19:13:16 +01:00
path . erase ( path . size ( ) - 1 ) ;
2017-06-21 12:09:50 +02:00
// simplify ".."
pos = 1 ; // don't simplify ".." if path starts with that
while ( ( pos = path . find ( " /.. " , pos ) ) ! = std : : string : : npos ) {
// not end of path, then string must be "/../"
if ( pos + 3 < path . size ( ) & & path [ pos + 3 ] ! = ' / ' ) {
+ + pos ;
continue ;
}
// get previous subpath
2022-03-22 21:14:48 +01:00
std : : string : : size_type pos1 = path . rfind ( ' / ' , pos - 1U ) ;
if ( pos1 = = std : : string : : npos ) {
pos1 = 0 ;
} else {
pos1 + = 1U ;
}
const std : : string previousSubPath = path . substr ( pos1 , pos - pos1 ) ;
2017-06-21 12:09:50 +02:00
if ( previousSubPath = = " .. " ) {
// don't simplify
+ + pos ;
2017-06-08 15:55:12 +02:00
} else {
2017-06-21 12:09:50 +02:00
// remove previous subpath and ".."
2022-03-22 21:14:48 +01:00
path . erase ( pos1 , pos - pos1 + 4 ) ;
2017-06-21 12:09:50 +02:00
if ( path . empty ( ) )
path = " . " ;
// update pos
pos = ( pos1 = = 0 ) ? 1 : ( pos1 - 1 ) ;
2016-12-06 14:10:57 +01:00
}
2016-07-24 11:36:02 +02:00
}
2016-07-24 09:59:57 +02:00
2017-06-21 12:09:50 +02:00
// Remove trailing '/'?
//if (path.size() > 1 && endsWith(path, "/"))
// path.erase(path.size()-1);
if ( unc )
path = ' / ' + path ;
2023-09-13 10:30:42 +02:00
// cppcheck-suppress duplicateExpressionTernary - platform-dependent implementation
2023-03-13 16:11:46 +01:00
return strpbrk ( path . c_str ( ) , " *? " ) = = nullptr ? realFilename ( path ) : path ;
2016-12-06 14:10:57 +01:00
}
2016-07-24 09:59:57 +02:00
}
2017-06-21 12:09:50 +02:00
/** Evaluate sizeof(type) */
static void simplifySizeof ( simplecpp : : TokenList & expr , const std : : map < std : : string , std : : size_t > & sizeOfType )
{
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; tok = tok - > next ) {
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) ! = " sizeof " )
2017-06-21 12:09:50 +02:00
continue ;
simplecpp : : Token * tok1 = tok - > next ;
if ( ! tok1 ) {
2017-08-21 18:43:42 +02:00
throw std : : runtime_error ( " missing sizeof argument " ) ;
2017-06-21 12:09:50 +02:00
}
simplecpp : : Token * tok2 = tok1 - > next ;
if ( ! tok2 ) {
2017-08-21 18:43:42 +02:00
throw std : : runtime_error ( " missing sizeof argument " ) ;
2017-06-21 12:09:50 +02:00
}
if ( tok1 - > op = = ' ( ' ) {
tok1 = tok1 - > next ;
2017-08-21 18:43:42 +02:00
while ( tok2 - > op ! = ' ) ' ) {
2017-06-21 12:09:50 +02:00
tok2 = tok2 - > next ;
2017-08-21 18:43:42 +02:00
if ( ! tok2 ) {
throw std : : runtime_error ( " invalid sizeof expression " ) ;
}
}
2017-06-21 12:09:50 +02:00
}
2016-12-06 14:10:57 +01:00
2017-06-21 12:09:50 +02:00
std : : string type ;
for ( simplecpp : : Token * typeToken = tok1 ; typeToken ! = tok2 ; typeToken = typeToken - > next ) {
2018-05-14 13:00:22 +02:00
if ( ( typeToken - > str ( ) = = " unsigned " | | typeToken - > str ( ) = = " signed " ) & & typeToken - > next - > name )
2016-12-06 14:10:57 +01:00
continue ;
2018-05-14 13:00:22 +02:00
if ( typeToken - > str ( ) = = " * " & & type . find ( ' * ' ) ! = std : : string : : npos )
2017-06-21 12:09:50 +02:00
continue ;
if ( ! type . empty ( ) )
type + = ' ' ;
2018-05-14 13:00:22 +02:00
type + = typeToken - > str ( ) ;
2016-12-06 14:10:57 +01:00
}
2017-06-21 12:09:50 +02:00
const std : : map < std : : string , std : : size_t > : : const_iterator it = sizeOfType . find ( type ) ;
if ( it ! = sizeOfType . end ( ) )
tok - > setstr ( toString ( it - > second ) ) ;
else
continue ;
tok2 = tok2 - > next ;
while ( tok - > next ! = tok2 )
expr . deleteToken ( tok - > next ) ;
2016-07-20 12:21:00 +02:00
}
2017-06-21 12:09:50 +02:00
}
2016-07-20 12:21:00 +02:00
2022-09-30 07:26:48 +02:00
/** Evaluate __has_include(file) */
static std : : string openHeader ( std : : ifstream & f , const simplecpp : : DUI & dui , const std : : string & sourcefile , const std : : string & header , bool systemheader ) ;
static void simplifyHasInclude ( simplecpp : : TokenList & expr , const simplecpp : : DUI & dui )
{
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; tok = tok - > next ) {
if ( tok - > str ( ) ! = " __has_include " )
continue ;
simplecpp : : Token * tok1 = tok - > next ;
if ( ! tok1 ) {
throw std : : runtime_error ( " missing __has_include argument " ) ;
}
simplecpp : : Token * tok2 = tok1 - > next ;
if ( ! tok2 ) {
throw std : : runtime_error ( " missing __has_include argument " ) ;
}
if ( tok1 - > op = = ' ( ' ) {
tok1 = tok1 - > next ;
while ( tok2 - > op ! = ' ) ' ) {
tok2 = tok2 - > next ;
if ( ! tok2 ) {
throw std : : runtime_error ( " invalid __has_include expression " ) ;
}
}
}
const std : : string & sourcefile = tok - > location . file ( ) ;
const bool systemheader = ( tok1 & & tok1 - > op = = ' < ' ) ;
std : : string header ;
if ( systemheader ) {
simplecpp : : Token * tok3 = tok1 - > next ;
if ( ! tok3 ) {
throw std : : runtime_error ( " missing __has_include closing angular bracket " ) ;
}
while ( tok3 - > op ! = ' > ' ) {
tok3 = tok3 - > next ;
if ( ! tok3 ) {
throw std : : runtime_error ( " invalid __has_include expression " ) ;
}
}
for ( simplecpp : : Token * headerToken = tok1 - > next ; headerToken ! = tok3 ; headerToken = headerToken - > next )
header + = headerToken - > str ( ) ;
2023-09-13 10:30:42 +02:00
// cppcheck-suppress selfAssignment - platform-dependent implementation
2022-09-30 07:26:48 +02:00
header = realFilename ( header ) ;
}
else {
header = realFilename ( tok1 - > str ( ) . substr ( 1U , tok1 - > str ( ) . size ( ) - 2U ) ) ;
}
std : : ifstream f ;
const std : : string header2 = openHeader ( f , dui , sourcefile , header , systemheader ) ;
tok - > setstr ( header2 . empty ( ) ? " 0 " : " 1 " ) ;
tok2 = tok2 - > next ;
while ( tok - > next ! = tok2 )
expr . deleteToken ( tok - > next ) ;
}
}
2018-01-13 18:08:23 +01:00
static const char * const altopData [ ] = { " and " , " or " , " bitand " , " bitor " , " compl " , " not " , " not_eq " , " xor " } ;
static const std : : set < std : : string > altop ( & altopData [ 0 ] , & altopData [ 8 ] ) ;
2017-06-21 12:09:50 +02:00
static void simplifyName ( simplecpp : : TokenList & expr )
{
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; tok = tok - > next ) {
if ( tok - > name ) {
2018-05-14 13:00:22 +02:00
if ( altop . find ( tok - > str ( ) ) ! = altop . end ( ) ) {
2017-06-21 12:09:50 +02:00
bool alt ;
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) = = " not " | | tok - > str ( ) = = " compl " ) {
alt = isAlternativeUnaryOp ( tok , tok - > str ( ) ) ;
2017-06-21 12:09:50 +02:00
} else {
2018-05-14 13:00:22 +02:00
alt = isAlternativeBinaryOp ( tok , tok - > str ( ) ) ;
2016-07-31 20:48:55 +02:00
}
2017-06-21 12:09:50 +02:00
if ( alt )
continue ;
2016-07-23 09:26:06 +02:00
}
2017-06-21 12:09:50 +02:00
tok - > setstr ( " 0 " ) ;
2016-07-23 09:26:06 +02:00
}
2016-07-20 12:21:00 +02:00
}
2017-06-21 12:09:50 +02:00
}
2016-07-20 12:21:00 +02:00
2021-04-30 17:41:59 +02:00
/*
* Reads at least minlen and at most maxlen digits ( inc . prefix ) in base base
* from s starting at position pos and converts them to a
* unsigned long long value , updating pos to point to the first
* unused element of s .
* Returns ULLONG_MAX if the result is not representable and
* throws if the above requirements were not possible to satisfy .
*/
static unsigned long long stringToULLbounded (
const std : : string & s ,
std : : size_t & pos ,
int base = 0 ,
std : : ptrdiff_t minlen = 1 ,
std : : size_t maxlen = std : : string : : npos
)
{
2022-09-30 07:26:48 +02:00
const std : : string sub = s . substr ( pos , maxlen ) ;
const char * const start = sub . c_str ( ) ;
2021-04-30 17:41:59 +02:00
char * end ;
2022-09-30 07:26:48 +02:00
const unsigned long long value = std : : strtoull ( start , & end , base ) ;
2021-04-30 17:41:59 +02:00
pos + = end - start ;
if ( end - start < minlen )
throw std : : runtime_error ( " expected digit " ) ;
return value ;
}
/* Converts character literal (including prefix, but not ud-suffix)
* to long long value .
*
2021-05-10 22:46:31 +02:00
* Assumes ASCII - compatible single - byte encoded str for narrow literals
* and UTF - 8 otherwise .
2021-04-30 17:41:59 +02:00
*
* For target assumes
2021-05-10 22:46:31 +02:00
* - execution character set encoding matching str
2021-04-30 17:41:59 +02:00
* - UTF - 32 execution wide - character set encoding
* - requirements for __STDC_UTF_16__ , __STDC_UTF_32__ and __STDC_ISO_10646__ satisfied
* - char16_t is 16 bit wide
* - char32_t is 32 bit wide
* - wchar_t is 32 bit wide and unsigned
* - matching char signedness to host
* - matching sizeof ( int ) to host
*
* For host assumes
* - ASCII - compatible execution character set
*
* For host and target assumes
* - CHAR_BIT = = 8
* - two ' s complement
*
* Implements multi - character narrow literals according to GCC ' s behavior ,
* except multi code unit universal character names are not supported .
* Multi - character wide literals are not supported .
* Limited support of universal character names for non - UTF - 8 execution character set encodings .
*/
long long simplecpp : : characterLiteralToLL ( const std : : string & str )
{
// default is wide/utf32
bool narrow = false ;
bool utf8 = false ;
bool utf16 = false ;
std : : size_t pos ;
2022-09-30 07:26:48 +02:00
if ( ! str . empty ( ) & & str [ 0 ] = = ' \' ' ) {
2021-04-30 17:41:59 +02:00
narrow = true ;
pos = 1 ;
} else if ( str . size ( ) > = 2 & & str [ 0 ] = = ' u ' & & str [ 1 ] = = ' \' ' ) {
utf16 = true ;
pos = 2 ;
} else if ( str . size ( ) > = 3 & & str [ 0 ] = = ' u ' & & str [ 1 ] = = ' 8 ' & & str [ 2 ] = = ' \' ' ) {
utf8 = true ;
pos = 3 ;
} else if ( str . size ( ) > = 2 & & ( str [ 0 ] = = ' L ' | | str [ 0 ] = = ' U ' ) & & str [ 1 ] = = ' \' ' ) {
pos = 2 ;
} else
throw std : : runtime_error ( " expected a character literal " ) ;
unsigned long long multivalue = 0 ;
std : : size_t nbytes = 0 ;
while ( pos + 1 < str . size ( ) ) {
if ( str [ pos ] = = ' \' ' | | str [ pos ] = = ' \n ' )
throw std : : runtime_error ( " raw single quotes and newlines not allowed in character literals " ) ;
if ( nbytes > = 1 & & ! narrow )
throw std : : runtime_error ( " multiple characters only supported in narrow character literals " ) ;
unsigned long long value ;
if ( str [ pos ] = = ' \\ ' ) {
pos + + ;
2022-09-30 07:26:48 +02:00
const char escape = str [ pos + + ] ;
2021-04-30 17:41:59 +02:00
if ( pos > = str . size ( ) )
throw std : : runtime_error ( " unexpected end of character literal " ) ;
switch ( escape ) {
2021-05-10 22:46:31 +02:00
// obscure GCC extensions
case ' % ' :
case ' ( ' :
case ' [ ' :
case ' { ' :
// standard escape sequences
2021-04-30 17:41:59 +02:00
case ' \' ' :
case ' " ' :
case ' ? ' :
case ' \\ ' :
value = static_cast < unsigned char > ( escape ) ;
break ;
case ' a ' :
value = static_cast < unsigned char > ( ' \a ' ) ;
break ;
case ' b ' :
value = static_cast < unsigned char > ( ' \b ' ) ;
break ;
case ' f ' :
value = static_cast < unsigned char > ( ' \f ' ) ;
break ;
case ' n ' :
value = static_cast < unsigned char > ( ' \n ' ) ;
break ;
case ' r ' :
value = static_cast < unsigned char > ( ' \r ' ) ;
break ;
case ' t ' :
value = static_cast < unsigned char > ( ' \t ' ) ;
break ;
case ' v ' :
value = static_cast < unsigned char > ( ' \v ' ) ;
break ;
2021-05-10 22:46:31 +02:00
// GCC extension for ESC character
2021-04-30 17:41:59 +02:00
case ' e ' :
2021-05-10 22:46:31 +02:00
case ' E ' :
2021-04-30 17:41:59 +02:00
value = static_cast < unsigned char > ( ' \x1b ' ) ;
break ;
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
// octal escape sequences consist of 1 to 3 digits
value = stringToULLbounded ( str , - - pos , 8 , 1 , 3 ) ;
break ;
case ' x ' :
// hexadecimal escape sequences consist of at least 1 digit
value = stringToULLbounded ( str , pos , 16 ) ;
break ;
case ' u ' :
case ' U ' : {
// universal character names have exactly 4 or 8 digits
2022-09-30 07:26:48 +02:00
const std : : size_t ndigits = ( escape = = ' u ' ? 4 : 8 ) ;
2021-04-30 17:41:59 +02:00
value = stringToULLbounded ( str , pos , 16 , ndigits , ndigits ) ;
// UTF-8 encodes code points above 0x7f in multiple code units
// code points above 0x10ffff are not allowed
if ( ( ( narrow | | utf8 ) & & value > 0x7f ) | | ( utf16 & & value > 0xffff ) | | value > 0x10ffff )
throw std : : runtime_error ( " code point too large " ) ;
if ( value > = 0xd800 & & value < = 0xdfff )
throw std : : runtime_error ( " surrogate code points not allowed in universal character names " ) ;
break ;
}
default :
throw std : : runtime_error ( " invalid escape sequence " ) ;
}
} else {
value = static_cast < unsigned char > ( str [ pos + + ] ) ;
2021-05-10 22:46:31 +02:00
if ( ! narrow & & value > = 0x80 ) {
// Assuming this is a UTF-8 encoded code point.
// This decoder may not completely validate the input.
// Noncharacters are neither rejected nor replaced.
2021-07-21 20:29:00 +02:00
2021-05-10 22:46:31 +02:00
int additional_bytes ;
if ( value > = 0xf5 ) // higher values would result in code points above 0x10ffff
throw std : : runtime_error ( " assumed UTF-8 encoded source, but sequence is invalid " ) ;
2022-09-30 07:26:48 +02:00
if ( value > = 0xf0 )
2021-05-10 22:46:31 +02:00
additional_bytes = 3 ;
else if ( value > = 0xe0 )
additional_bytes = 2 ;
else if ( value > = 0xc2 ) // 0xc0 and 0xc1 are always overlong 2-bytes encodings
additional_bytes = 1 ;
else
throw std : : runtime_error ( " assumed UTF-8 encoded source, but sequence is invalid " ) ;
2021-07-21 20:29:00 +02:00
2021-05-10 22:46:31 +02:00
value & = ( 1 < < ( 6 - additional_bytes ) ) - 1 ;
while ( additional_bytes - - ) {
2021-07-21 20:29:00 +02:00
if ( pos + 1 > = str . size ( ) )
2021-05-10 22:46:31 +02:00
throw std : : runtime_error ( " assumed UTF-8 encoded source, but character literal ends unexpectedly " ) ;
2021-07-21 20:29:00 +02:00
2022-09-30 07:26:48 +02:00
const unsigned char c = str [ pos + + ] ;
2021-07-21 20:29:00 +02:00
2021-05-10 22:46:31 +02:00
if ( ( ( c > > 6 ) ! = 2 ) // ensure c has form 0xb10xxxxxx
| | ( ! value & & additional_bytes = = 1 & & c < 0xa0 ) // overlong 3-bytes encoding
| | ( ! value & & additional_bytes = = 2 & & c < 0x90 ) ) // overlong 4-bytes encoding
throw std : : runtime_error ( " assumed UTF-8 encoded source, but sequence is invalid " ) ;
2021-07-21 20:29:00 +02:00
2021-05-10 22:46:31 +02:00
value = ( value < < 6 ) | ( c & ( ( 1 < < 7 ) - 1 ) ) ;
}
if ( value > = 0xd800 & & value < = 0xdfff )
throw std : : runtime_error ( " assumed UTF-8 encoded source, but sequence is invalid " ) ;
2021-07-21 20:29:00 +02:00
2021-05-10 22:46:31 +02:00
if ( ( utf8 & & value > 0x7f ) | | ( utf16 & & value > 0xffff ) | | value > 0x10ffff )
throw std : : runtime_error ( " code point too large " ) ;
}
2021-04-30 17:41:59 +02:00
}
if ( ( ( narrow | | utf8 ) & & value > std : : numeric_limits < unsigned char > : : max ( ) ) | | ( utf16 & & value > > 16 ) | | value > > 32 )
throw std : : runtime_error ( " numeric escape sequence too large " ) ;
multivalue < < = CHAR_BIT ;
multivalue | = value ;
nbytes + + ;
}
if ( pos + 1 ! = str . size ( ) | | str [ pos ] ! = ' \' ' )
throw std : : runtime_error ( " missing closing quote in character literal " ) ;
if ( ! nbytes )
throw std : : runtime_error ( " empty character literal " ) ;
// ordinary narrow character literal's value is determined by (possibly signed) char
if ( narrow & & nbytes = = 1 )
return static_cast < char > ( multivalue ) ;
// while multi-character literal's value is determined by (signed) int
if ( narrow )
return static_cast < int > ( multivalue ) ;
// All other cases are unsigned. Since long long is at least 64bit wide,
// while the literals at most 32bit wide, the conversion preserves all values.
return multivalue ;
}
2017-06-21 12:09:50 +02:00
static void simplifyNumbers ( simplecpp : : TokenList & expr )
{
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; tok = tok - > next ) {
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) . size ( ) = = 1U )
2017-06-21 12:09:50 +02:00
continue ;
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) . compare ( 0 , 2 , " 0x " ) = = 0 )
tok - > setstr ( toString ( stringToULL ( tok - > str ( ) ) ) ) ;
2022-09-30 07:26:48 +02:00
else if ( ! tok - > number & & tok - > str ( ) . find ( ' \' ' ) ! = std : : string : : npos )
2021-04-30 17:41:59 +02:00
tok - > setstr ( toString ( simplecpp : : characterLiteralToLL ( tok - > str ( ) ) ) ) ;
2016-07-20 12:21:00 +02:00
}
2017-06-21 12:09:50 +02:00
}
2016-07-20 12:21:00 +02:00
2022-07-27 21:46:03 +02:00
static void simplifyComments ( simplecpp : : TokenList & expr )
{
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; ) {
2022-09-30 07:26:48 +02:00
simplecpp : : Token * const d = tok ;
2022-07-27 21:46:03 +02:00
tok = tok - > next ;
if ( d - > comment )
expr . deleteToken ( d ) ;
}
}
2022-09-30 07:26:48 +02:00
static long long evaluate ( simplecpp : : TokenList & expr , const simplecpp : : DUI & dui , const std : : map < std : : string , std : : size_t > & sizeOfType )
2017-06-21 12:09:50 +02:00
{
2022-07-27 21:46:03 +02:00
simplifyComments ( expr ) ;
2017-06-21 12:09:50 +02:00
simplifySizeof ( expr , sizeOfType ) ;
2022-09-30 07:26:48 +02:00
simplifyHasInclude ( expr , dui ) ;
2017-06-21 12:09:50 +02:00
simplifyName ( expr ) ;
simplifyNumbers ( expr ) ;
expr . constFold ( ) ;
// TODO: handle invalid expressions
2018-05-14 13:00:22 +02:00
return expr . cfront ( ) & & expr . cfront ( ) = = expr . cback ( ) & & expr . cfront ( ) - > number ? stringToLL ( expr . cfront ( ) - > str ( ) ) : 0LL ;
2017-06-21 12:09:50 +02:00
}
2016-07-20 12:21:00 +02:00
2017-06-21 12:09:50 +02:00
static const simplecpp : : Token * gotoNextLine ( const simplecpp : : Token * tok )
{
const unsigned int line = tok - > location . line ;
const unsigned int file = tok - > location . fileIndex ;
while ( tok & & tok - > location . line = = line & & tok - > location . fileIndex = = file )
tok = tok - > next ;
return tok ;
}
2016-12-06 14:10:57 +01:00
2019-03-10 08:47:27 +01:00
# ifdef SIMPLECPP_WINDOWS
class NonExistingFilesCache {
public :
2023-09-13 10:30:42 +02:00
NonExistingFilesCache ( ) { }
2019-03-10 08:47:27 +01:00
bool contains ( const std : : string & path ) {
2023-09-13 10:30:42 +02:00
MyLock < MyMutex > lock ( m_mutex ) ;
2019-03-10 08:47:27 +01:00
return ( m_pathSet . find ( path ) ! = m_pathSet . end ( ) ) ;
}
void add ( const std : : string & path ) {
2023-09-13 10:30:42 +02:00
MyLock < MyMutex > lock ( m_mutex ) ;
2019-03-10 08:47:27 +01:00
m_pathSet . insert ( path ) ;
}
2023-01-20 15:41:32 +01:00
void clear ( ) {
2023-09-13 10:30:42 +02:00
MyLock < MyMutex > lock ( m_mutex ) ;
2023-01-20 15:41:32 +01:00
m_pathSet . clear ( ) ;
}
2019-03-10 08:47:27 +01:00
private :
std : : set < std : : string > m_pathSet ;
2023-09-13 10:30:42 +02:00
MyMutex m_mutex ;
2019-03-10 08:47:27 +01:00
} ;
static NonExistingFilesCache nonExistingFilesCache ;
# endif
2022-03-22 21:14:48 +01:00
static std : : string openHeader ( std : : ifstream & f , const std : : string & path )
2019-03-10 08:47:27 +01:00
{
std : : string simplePath = simplecpp : : simplifyPath ( path ) ;
2023-01-20 15:41:32 +01:00
# ifdef SIMPLECPP_WINDOWS
2019-03-10 08:47:27 +01:00
if ( nonExistingFilesCache . contains ( simplePath ) )
return " " ; // file is known not to exist, skip expensive file open call
2023-01-20 15:41:32 +01:00
# endif
2019-03-10 08:47:27 +01:00
f . open ( simplePath . c_str ( ) ) ;
if ( f . is_open ( ) )
return simplePath ;
2023-01-20 15:41:32 +01:00
# ifdef SIMPLECPP_WINDOWS
nonExistingFilesCache . add ( simplePath ) ;
2019-03-10 08:47:27 +01:00
# endif
2023-01-20 15:41:32 +01:00
return " " ;
2019-03-10 08:47:27 +01:00
}
2020-09-14 15:43:43 +02:00
static std : : string getRelativeFileName ( const std : : string & sourcefile , const std : : string & header )
{
if ( sourcefile . find_first_of ( " \\ / " ) ! = std : : string : : npos )
return simplecpp : : simplifyPath ( sourcefile . substr ( 0 , sourcefile . find_last_of ( " \\ / " ) + 1U ) + header ) ;
return simplecpp : : simplifyPath ( header ) ;
}
2020-09-11 18:28:37 +02:00
static std : : string openHeaderRelative ( std : : ifstream & f , const std : : string & sourcefile , const std : : string & header )
2017-06-21 12:09:50 +02:00
{
2022-03-22 21:14:48 +01:00
return openHeader ( f , getRelativeFileName ( sourcefile , header ) ) ;
2020-09-14 15:43:43 +02:00
}
static std : : string getIncludePathFileName ( const std : : string & includePath , const std : : string & header )
{
std : : string path = includePath ;
if ( ! path . empty ( ) & & path [ path . size ( ) - 1U ] ! = ' / ' & & path [ path . size ( ) - 1U ] ! = ' \\ ' )
path + = ' / ' ;
return path + header ;
2020-09-11 18:28:37 +02:00
}
2016-07-20 12:21:00 +02:00
2020-09-11 18:28:37 +02:00
static std : : string openHeaderIncludePath ( std : : ifstream & f , const simplecpp : : DUI & dui , const std : : string & header )
{
2017-06-21 12:09:50 +02:00
for ( std : : list < std : : string > : : const_iterator it = dui . includePaths . begin ( ) ; it ! = dui . includePaths . end ( ) ; + + it ) {
2022-03-22 21:14:48 +01:00
std : : string simplePath = openHeader ( f , getIncludePathFileName ( * it , header ) ) ;
2019-03-10 08:47:27 +01:00
if ( ! simplePath . empty ( ) )
return simplePath ;
2016-07-20 12:21:00 +02:00
}
2017-06-21 12:09:50 +02:00
return " " ;
}
2020-09-11 18:28:37 +02:00
static std : : string openHeader ( std : : ifstream & f , const simplecpp : : DUI & dui , const std : : string & sourcefile , const std : : string & header , bool systemheader )
{
if ( isAbsolutePath ( header ) )
2022-03-22 21:14:48 +01:00
return openHeader ( f , header ) ;
2020-09-11 18:28:37 +02:00
std : : string ret ;
if ( systemheader ) {
ret = openHeaderIncludePath ( f , dui , header ) ;
2022-12-09 07:18:13 +01:00
return ret ;
2020-09-11 18:28:37 +02:00
}
ret = openHeaderRelative ( f , sourcefile , header ) ;
2022-12-09 07:18:13 +01:00
if ( ret . empty ( ) )
return openHeaderIncludePath ( f , dui , header ) ;
return ret ;
2020-09-11 18:28:37 +02:00
}
2017-06-21 12:09:50 +02:00
static std : : string getFileName ( const std : : map < std : : string , simplecpp : : TokenList * > & filedata , const std : : string & sourcefile , const std : : string & header , const simplecpp : : DUI & dui , bool systemheader )
{
2018-01-13 18:08:23 +01:00
if ( filedata . empty ( ) ) {
return " " ;
}
2017-06-23 20:09:26 +02:00
if ( isAbsolutePath ( header ) ) {
2017-06-21 12:09:50 +02:00
return ( filedata . find ( header ) ! = filedata . end ( ) ) ? simplecpp : : simplifyPath ( header ) : " " ;
}
2016-07-20 12:21:00 +02:00
2020-09-14 15:43:43 +02:00
const std : : string relativeFilename = getRelativeFileName ( sourcefile , header ) ;
if ( ! systemheader & & filedata . find ( relativeFilename ) ! = filedata . end ( ) )
return relativeFilename ;
2016-07-20 12:21:00 +02:00
2017-06-21 12:09:50 +02:00
for ( std : : list < std : : string > : : const_iterator it = dui . includePaths . begin ( ) ; it ! = dui . includePaths . end ( ) ; + + it ) {
2020-09-14 15:43:43 +02:00
std : : string s = simplecpp : : simplifyPath ( getIncludePathFileName ( * it , header ) ) ;
2017-06-21 12:09:50 +02:00
if ( filedata . find ( s ) ! = filedata . end ( ) )
return s ;
2016-12-06 14:10:57 +01:00
}
2017-06-21 12:09:50 +02:00
2023-01-20 15:41:32 +01:00
if ( systemheader & & filedata . find ( header ) ! = filedata . end ( ) )
return header ;
2020-09-14 15:43:43 +02:00
2017-06-21 12:09:50 +02:00
return " " ;
}
static bool hasFile ( const std : : map < std : : string , simplecpp : : TokenList * > & filedata , const std : : string & sourcefile , const std : : string & header , const simplecpp : : DUI & dui , bool systemheader )
{
return ! getFileName ( filedata , sourcefile , header , dui , systemheader ) . empty ( ) ;
2016-07-20 12:21:00 +02:00
}
2022-09-30 07:26:48 +02:00
std : : map < std : : string , simplecpp : : TokenList * > simplecpp : : load ( const simplecpp : : TokenList & rawtokens , std : : vector < std : : string > & filenames , const simplecpp : : DUI & dui , simplecpp : : OutputList * outputList )
2016-07-20 12:21:00 +02:00
{
2023-01-20 15:41:32 +01:00
# ifdef SIMPLECPP_WINDOWS
if ( dui . clearIncludeCache )
2023-09-13 10:30:42 +02:00
nonExistingFilesCache . clear ( ) ;
2023-01-20 15:41:32 +01:00
# endif
2016-07-20 12:21:00 +02:00
std : : map < std : : string , simplecpp : : TokenList * > ret ;
std : : list < const Token * > filelist ;
2016-08-06 08:41:19 +02:00
// -include files
for ( std : : list < std : : string > : : const_iterator it = dui . includes . begin ( ) ; it ! = dui . includes . end ( ) ; + + it ) {
2016-08-21 17:08:40 +02:00
const std : : string & filename = realFilename ( * it ) ;
2016-08-17 21:16:29 +02:00
if ( ret . find ( filename ) ! = ret . end ( ) )
2016-08-06 08:41:19 +02:00
continue ;
2016-08-17 21:16:29 +02:00
std : : ifstream fin ( filename . c_str ( ) ) ;
2019-12-09 19:16:55 +01:00
if ( ! fin . is_open ( ) ) {
if ( outputList ) {
2022-09-30 07:26:48 +02:00
simplecpp : : Output err ( filenames ) ;
2019-12-09 19:16:55 +01:00
err . type = simplecpp : : Output : : EXPLICIT_INCLUDE_NOT_FOUND ;
2022-09-30 07:26:48 +02:00
err . location = Location ( filenames ) ;
2019-12-09 19:16:55 +01:00
err . msg = " Can not open include file ' " + filename + " ' that is explicitly included. " ;
outputList - > push_back ( err ) ;
}
2016-08-06 08:41:19 +02:00
continue ;
2019-12-09 19:16:55 +01:00
}
2023-03-13 16:11:46 +01:00
fin . close ( ) ;
2016-08-06 08:41:19 +02:00
2023-03-13 16:11:46 +01:00
TokenList * tokenlist = new TokenList ( filename , filenames , outputList ) ;
2016-08-06 08:41:19 +02:00
if ( ! tokenlist - > front ( ) ) {
delete tokenlist ;
continue ;
}
2016-08-17 21:16:29 +02:00
ret [ filename ] = tokenlist ;
2016-08-06 08:41:19 +02:00
filelist . push_back ( tokenlist - > front ( ) ) ;
}
2022-03-22 21:14:48 +01:00
for ( const Token * rawtok = rawtokens . cfront ( ) ; rawtok | | ! filelist . empty ( ) ; rawtok = rawtok ? rawtok - > next : nullptr ) {
if ( rawtok = = nullptr ) {
2016-07-20 12:21:00 +02:00
rawtok = filelist . back ( ) ;
filelist . pop_back ( ) ;
}
2016-07-21 18:58:11 +02:00
if ( rawtok - > op ! = ' # ' | | sameline ( rawtok - > previousSkipComments ( ) , rawtok ) )
2016-07-20 12:21:00 +02:00
continue ;
2016-07-21 18:58:11 +02:00
rawtok = rawtok - > nextSkipComments ( ) ;
2018-05-14 13:00:22 +02:00
if ( ! rawtok | | rawtok - > str ( ) ! = INCLUDE )
2016-07-20 12:21:00 +02:00
continue ;
const std : : string & sourcefile = rawtok - > location . file ( ) ;
2022-09-30 07:26:48 +02:00
const Token * const htok = rawtok - > nextSkipComments ( ) ;
2016-07-21 18:58:11 +02:00
if ( ! sameline ( rawtok , htok ) )
continue ;
2022-09-30 07:26:48 +02:00
const bool systemheader = ( htok - > str ( ) [ 0 ] = = ' < ' ) ;
2018-05-14 13:00:22 +02:00
const std : : string header ( realFilename ( htok - > str ( ) . substr ( 1U , htok - > str ( ) . size ( ) - 2U ) ) ) ;
2016-07-21 21:04:54 +02:00
if ( hasFile ( ret , sourcefile , header , dui , systemheader ) )
2016-07-20 12:21:00 +02:00
continue ;
std : : ifstream f ;
2019-05-07 19:15:31 +02:00
const std : : string header2 = openHeader ( f , dui , sourcefile , header , systemheader ) ;
2016-07-20 12:21:00 +02:00
if ( ! f . is_open ( ) )
continue ;
2023-03-13 16:11:46 +01:00
f . close ( ) ;
2016-07-20 12:21:00 +02:00
2023-03-13 16:11:46 +01:00
TokenList * tokens = new TokenList ( header2 , filenames , outputList ) ;
2016-07-20 12:21:00 +02:00
ret [ header2 ] = tokens ;
2016-07-29 08:46:38 +02:00
if ( tokens - > front ( ) )
filelist . push_back ( tokens - > front ( ) ) ;
2016-07-20 12:21:00 +02:00
}
return ret ;
}
2022-03-22 21:14:48 +01:00
static bool preprocessToken ( simplecpp : : TokenList & output , const simplecpp : : Token * * tok1 , simplecpp : : MacroMap & macros , std : : vector < std : : string > & files , simplecpp : : OutputList * outputList )
2016-12-06 14:10:57 +01:00
{
2022-09-30 07:26:48 +02:00
const simplecpp : : Token * const tok = * tok1 ;
2022-03-22 21:14:48 +01:00
const simplecpp : : MacroMap : : const_iterator it = macros . find ( tok - > str ( ) ) ;
2016-09-03 12:29:45 +02:00
if ( it ! = macros . end ( ) ) {
simplecpp : : TokenList value ( files ) ;
try {
* tok1 = it - > second . expand ( & value , tok , macros , files ) ;
} catch ( simplecpp : : Macro : : Error & err ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
simplecpp : : Output out ( files ) ;
out . type = simplecpp : : Output : : SYNTAX_ERROR ;
out . location = err . location ;
2018-05-14 13:00:22 +02:00
out . msg = " failed to expand \' " + tok - > str ( ) + " \' , " + err . what ;
2016-09-03 12:29:45 +02:00
outputList - > push_back ( out ) ;
2016-12-06 14:10:57 +01:00
}
2016-09-03 12:29:45 +02:00
return false ;
}
output . takeTokens ( value ) ;
} else {
if ( ! tok - > comment )
output . push_back ( new simplecpp : : Token ( * tok ) ) ;
* tok1 = tok - > next ;
}
return true ;
}
2022-07-27 21:46:03 +02:00
static void getLocaltime ( struct tm & ltime )
{
2022-03-22 21:14:48 +01:00
time_t t ;
time ( & t ) ;
# ifndef _WIN32
2023-09-13 10:30:42 +02:00
// NOLINTNEXTLINE(misc-include-cleaner) - false positive
2022-03-22 21:14:48 +01:00
localtime_r ( & t , & ltime ) ;
# else
localtime_s ( & ltime , & t ) ;
# endif
}
2023-09-13 10:30:42 +02:00
static std : : string getDateDefine ( const struct tm * timep )
2022-07-27 21:46:03 +02:00
{
2022-03-22 21:14:48 +01:00
char buf [ ] = " ??? ?? ???? " ;
strftime ( buf , sizeof ( buf ) , " %b %d %Y " , timep ) ;
return std : : string ( " \" " ) . append ( buf ) . append ( " \" " ) ;
}
2023-09-13 10:30:42 +02:00
static std : : string getTimeDefine ( const struct tm * timep )
2022-07-27 21:46:03 +02:00
{
2022-03-22 21:14:48 +01:00
char buf [ ] = " ??:??:?? " ;
strftime ( buf , sizeof ( buf ) , " %T " , timep ) ;
return std : : string ( " \" " ) . append ( buf ) . append ( " \" " ) ;
}
2021-07-21 20:29:00 +02:00
void simplecpp : : preprocess ( simplecpp : : TokenList & output , const simplecpp : : TokenList & rawtokens , std : : vector < std : : string > & files , std : : map < std : : string , simplecpp : : TokenList * > & filedata , const simplecpp : : DUI & dui , simplecpp : : OutputList * outputList , std : : list < simplecpp : : MacroUsage > * macroUsage , std : : list < simplecpp : : IfCond > * ifCond )
2016-07-20 12:21:00 +02:00
{
2023-01-20 15:41:32 +01:00
# ifdef SIMPLECPP_WINDOWS
if ( dui . clearIncludeCache )
nonExistingFilesCache . clear ( ) ;
# endif
2016-07-20 20:07:16 +02:00
std : : map < std : : string , std : : size_t > sizeOfType ( rawtokens . sizeOfType ) ;
2019-07-03 17:03:46 +02:00
sizeOfType . insert ( std : : make_pair ( " char " , sizeof ( char ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " short " , sizeof ( short ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " short int " , sizeOfType [ " short " ] ) ) ;
sizeOfType . insert ( std : : make_pair ( " int " , sizeof ( int ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " long " , sizeof ( long ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " long int " , sizeOfType [ " long " ] ) ) ;
sizeOfType . insert ( std : : make_pair ( " long long " , sizeof ( long long ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " float " , sizeof ( float ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " double " , sizeof ( double ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " long double " , sizeof ( long double ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " char * " , sizeof ( char * ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " short * " , sizeof ( short * ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " short int * " , sizeOfType [ " short * " ] ) ) ;
sizeOfType . insert ( std : : make_pair ( " int * " , sizeof ( int * ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " long * " , sizeof ( long * ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " long int * " , sizeOfType [ " long * " ] ) ) ;
sizeOfType . insert ( std : : make_pair ( " long long * " , sizeof ( long long * ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " float * " , sizeof ( float * ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " double * " , sizeof ( double * ) ) ) ;
sizeOfType . insert ( std : : make_pair ( " long double * " , sizeof ( long double * ) ) ) ;
2016-07-20 20:07:16 +02:00
2021-04-26 16:25:39 +02:00
const bool hasInclude = ( dui . std . size ( ) = = 5 & & dui . std . compare ( 0 , 3 , " c++ " ) = = 0 & & dui . std > = " c++17 " ) ;
2022-03-22 21:14:48 +01:00
MacroMap macros ;
2016-07-20 12:21:00 +02:00
for ( std : : list < std : : string > : : const_iterator it = dui . defines . begin ( ) ; it ! = dui . defines . end ( ) ; + + it ) {
const std : : string & macrostr = * it ;
2016-12-04 12:10:28 +01:00
const std : : string : : size_type eq = macrostr . find ( ' = ' ) ;
const std : : string : : size_type par = macrostr . find ( ' ( ' ) ;
2016-07-20 12:21:00 +02:00
const std : : string macroname = macrostr . substr ( 0 , std : : min ( eq , par ) ) ;
if ( dui . undefined . find ( macroname ) ! = dui . undefined . end ( ) )
continue ;
const std : : string lhs ( macrostr . substr ( 0 , eq ) ) ;
const std : : string rhs ( eq = = std : : string : : npos ? std : : string ( " 1 " ) : macrostr . substr ( eq + 1 ) ) ;
const Macro macro ( lhs , rhs , files ) ;
macros . insert ( std : : pair < TokenString , Macro > ( macro . name ( ) , macro ) ) ;
}
2019-07-03 17:03:46 +02:00
macros . insert ( std : : make_pair ( " __FILE__ " , Macro ( " __FILE__ " , " __FILE__ " , files ) ) ) ;
macros . insert ( std : : make_pair ( " __LINE__ " , Macro ( " __LINE__ " , " __LINE__ " , files ) ) ) ;
macros . insert ( std : : make_pair ( " __COUNTER__ " , Macro ( " __COUNTER__ " , " __COUNTER__ " , files ) ) ) ;
2022-03-22 21:14:48 +01:00
struct tm ltime = { } ;
getLocaltime ( ltime ) ;
macros . insert ( std : : make_pair ( " __DATE__ " , Macro ( " __DATE__ " , getDateDefine ( & ltime ) , files ) ) ) ;
macros . insert ( std : : make_pair ( " __TIME__ " , Macro ( " __TIME__ " , getTimeDefine ( & ltime ) , files ) ) ) ;
if ( ! dui . std . empty ( ) ) {
std : : string std_def = simplecpp : : getCStdString ( dui . std ) ;
if ( ! std_def . empty ( ) ) {
macros . insert ( std : : make_pair ( " __STDC_VERSION__ " , Macro ( " __STDC_VERSION__ " , std_def , files ) ) ) ;
} else {
std_def = simplecpp : : getCppStdString ( dui . std ) ;
if ( ! std_def . empty ( ) )
macros . insert ( std : : make_pair ( " __cplusplus " , Macro ( " __cplusplus " , std_def , files ) ) ) ;
}
}
2021-04-26 16:25:39 +02:00
2023-04-05 21:17:48 +02:00
// True => code in current #if block should be kept
// ElseIsTrue => code in current #if block should be dropped. the code in the #else should be kept.
// AlwaysFalse => drop all code in #if and #else
enum IfState { True , ElseIsTrue , AlwaysFalse } ;
2016-07-21 15:05:29 +02:00
std : : stack < int > ifstates ;
2023-04-05 21:17:48 +02:00
ifstates . push ( True ) ;
2016-07-20 12:21:00 +02:00
std : : stack < const Token * > includetokenstack ;
2016-07-21 12:47:00 +02:00
std : : set < std : : string > pragmaOnce ;
2016-08-06 08:41:19 +02:00
includetokenstack . push ( rawtokens . cfront ( ) ) ;
for ( std : : list < std : : string > : : const_iterator it = dui . includes . begin ( ) ; it ! = dui . includes . end ( ) ; + + it ) {
const std : : map < std : : string , TokenList * > : : const_iterator f = filedata . find ( * it ) ;
if ( f ! = filedata . end ( ) )
includetokenstack . push ( f - > second - > cfront ( ) ) ;
}
2022-03-22 21:14:48 +01:00
std : : map < std : : string , std : : list < Location > > maybeUsedMacros ;
for ( const Token * rawtok = nullptr ; rawtok | | ! includetokenstack . empty ( ) ; ) {
if ( rawtok = = nullptr ) {
2016-07-20 12:21:00 +02:00
rawtok = includetokenstack . top ( ) ;
includetokenstack . pop ( ) ;
continue ;
}
2023-04-18 20:15:24 +02:00
if ( rawtok - > op = = ' # ' & & ! sameline ( rawtok - > previousSkipComments ( ) , rawtok ) ) {
2018-04-17 08:12:15 +02:00
if ( ! sameline ( rawtok , rawtok - > next ) ) {
rawtok = rawtok - > next ;
continue ;
}
2016-07-20 12:21:00 +02:00
rawtok = rawtok - > next ;
2018-04-17 08:12:15 +02:00
if ( ! rawtok - > name ) {
rawtok = gotoNextLine ( rawtok ) ;
2016-07-20 12:21:00 +02:00
continue ;
2016-07-25 09:13:59 +02:00
}
2016-07-20 12:21:00 +02:00
2018-05-14 13:00:22 +02:00
if ( ifstates . size ( ) < = 1U & & ( rawtok - > str ( ) = = ELIF | | rawtok - > str ( ) = = ELSE | | rawtok - > str ( ) = = ENDIF ) ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
simplecpp : : Output err ( files ) ;
err . type = Output : : SYNTAX_ERROR ;
err . location = rawtok - > location ;
2018-05-14 13:00:22 +02:00
err . msg = " # " + rawtok - > str ( ) + " without #if " ;
2016-12-04 12:10:28 +01:00
outputList - > push_back ( err ) ;
2016-12-06 14:10:57 +01:00
}
2016-12-04 12:10:28 +01:00
output . clear ( ) ;
return ;
}
2023-04-05 21:17:48 +02:00
if ( ifstates . top ( ) = = True & & ( rawtok - > str ( ) = = ERROR | | rawtok - > str ( ) = = WARNING ) ) {
2016-07-20 12:21:00 +02:00
if ( outputList ) {
simplecpp : : Output err ( rawtok - > location . files ) ;
2018-05-14 13:00:22 +02:00
err . type = rawtok - > str ( ) = = ERROR ? Output : : ERROR : Output : : WARNING ;
2016-07-20 12:21:00 +02:00
err . location = rawtok - > location ;
for ( const Token * tok = rawtok - > next ; tok & & sameline ( rawtok , tok ) ; tok = tok - > next ) {
2018-05-14 13:00:22 +02:00
if ( ! err . msg . empty ( ) & & isNameChar ( tok - > str ( ) [ 0 ] ) )
2016-07-20 12:21:00 +02:00
err . msg + = ' ' ;
2018-05-14 13:00:22 +02:00
err . msg + = tok - > str ( ) ;
2016-07-20 12:21:00 +02:00
}
2018-05-14 13:00:22 +02:00
err . msg = ' # ' + rawtok - > str ( ) + ' ' + err . msg ;
2016-07-20 12:21:00 +02:00
outputList - > push_back ( err ) ;
}
2018-05-14 13:00:22 +02:00
if ( rawtok - > str ( ) = = ERROR ) {
2016-08-11 19:00:35 +02:00
output . clear ( ) ;
return ;
}
2016-07-20 12:21:00 +02:00
}
2018-05-14 13:00:22 +02:00
if ( rawtok - > str ( ) = = DEFINE ) {
2023-04-05 21:17:48 +02:00
if ( ifstates . top ( ) ! = True )
2016-07-20 12:21:00 +02:00
continue ;
try {
const Macro & macro = Macro ( rawtok - > previous , files ) ;
if ( dui . undefined . find ( macro . name ( ) ) = = dui . undefined . end ( ) ) {
2022-09-30 07:26:48 +02:00
const MacroMap : : iterator it = macros . find ( macro . name ( ) ) ;
2016-07-20 12:21:00 +02:00
if ( it = = macros . end ( ) )
macros . insert ( std : : pair < TokenString , Macro > ( macro . name ( ) , macro ) ) ;
else
it - > second = macro ;
}
} catch ( const std : : runtime_error & ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
simplecpp : : Output err ( files ) ;
err . type = Output : : SYNTAX_ERROR ;
err . location = rawtok - > location ;
err . msg = " Failed to parse #define " ;
2016-11-10 20:04:05 +01:00
outputList - > push_back ( err ) ;
2016-12-06 14:10:57 +01:00
}
2016-11-10 20:04:05 +01:00
output . clear ( ) ;
return ;
2016-07-20 12:21:00 +02:00
}
2023-04-05 21:17:48 +02:00
} else if ( ifstates . top ( ) = = True & & rawtok - > str ( ) = = INCLUDE ) {
2016-09-03 12:29:45 +02:00
TokenList inc1 ( files ) ;
for ( const Token * inctok = rawtok - > next ; sameline ( rawtok , inctok ) ; inctok = inctok - > next ) {
if ( ! inctok - > comment )
inc1 . push_back ( new Token ( * inctok ) ) ;
}
TokenList inc2 ( files ) ;
if ( ! inc1 . empty ( ) & & inc1 . cfront ( ) - > name ) {
const Token * inctok = inc1 . cfront ( ) ;
if ( ! preprocessToken ( inc2 , & inctok , macros , files , outputList ) ) {
output . clear ( ) ;
return ;
}
} else {
inc2 . takeTokens ( inc1 ) ;
}
2018-02-11 15:48:37 +01:00
if ( ! inc2 . empty ( ) & & inc2 . cfront ( ) - > op = = ' < ' & & inc2 . cback ( ) - > op = = ' > ' ) {
TokenString hdr ;
// TODO: Sometimes spaces must be added in the string
// Somehow preprocessToken etc must be told that the location should be source location not destination location
for ( const Token * tok = inc2 . cfront ( ) ; tok ; tok = tok - > next ) {
2018-05-14 13:00:22 +02:00
hdr + = tok - > str ( ) ;
2018-02-11 15:48:37 +01:00
}
inc2 . clear ( ) ;
inc2 . push_back ( new Token ( hdr , inc1 . cfront ( ) - > location ) ) ;
2018-03-15 21:34:58 +01:00
inc2 . front ( ) - > op = ' < ' ;
2018-02-11 15:48:37 +01:00
}
2018-05-14 13:00:22 +02:00
if ( inc2 . empty ( ) | | inc2 . cfront ( ) - > str ( ) . size ( ) < = 2U ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
simplecpp : : Output err ( files ) ;
err . type = Output : : SYNTAX_ERROR ;
err . location = rawtok - > location ;
err . msg = " No header in #include " ;
2016-09-03 12:29:45 +02:00
outputList - > push_back ( err ) ;
2016-12-06 14:10:57 +01:00
}
2016-09-03 12:29:45 +02:00
output . clear ( ) ;
return ;
}
2022-09-30 07:26:48 +02:00
const Token * const inctok = inc2 . cfront ( ) ;
2016-09-03 12:29:45 +02:00
2023-01-20 15:41:32 +01:00
const bool systemheader = ( inctok - > str ( ) [ 0 ] = = ' < ' ) ;
2018-05-14 13:00:22 +02:00
const std : : string header ( realFilename ( inctok - > str ( ) . substr ( 1U , inctok - > str ( ) . size ( ) - 2U ) ) ) ;
2016-11-10 20:04:05 +01:00
std : : string header2 = getFileName ( filedata , rawtok - > location . file ( ) , header , dui , systemheader ) ;
if ( header2 . empty ( ) ) {
// try to load file..
std : : ifstream f ;
2019-05-07 19:15:31 +02:00
header2 = openHeader ( f , dui , rawtok - > location . file ( ) , header , systemheader ) ;
2016-11-10 20:04:05 +01:00
if ( f . is_open ( ) ) {
2022-09-30 07:26:48 +02:00
TokenList * const tokens = new TokenList ( f , files , header2 , outputList ) ;
2016-11-10 20:04:05 +01:00
filedata [ header2 ] = tokens ;
}
}
2016-07-31 12:10:30 +02:00
if ( header2 . empty ( ) ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
simplecpp : : Output out ( files ) ;
out . type = Output : : MISSING_HEADER ;
out . location = rawtok - > location ;
2018-05-14 13:00:22 +02:00
out . msg = " Header not found: " + inctok - > str ( ) ;
2016-12-06 14:10:57 +01:00
outputList - > push_back ( out ) ;
}
2016-07-31 12:10:30 +02:00
} else if ( includetokenstack . size ( ) > = 400 ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
simplecpp : : Output out ( files ) ;
out . type = Output : : INCLUDE_NESTED_TOO_DEEPLY ;
out . location = rawtok - > location ;
out . msg = " #include nested too deeply " ;
2016-07-31 12:10:30 +02:00
outputList - > push_back ( out ) ;
2016-12-06 14:10:57 +01:00
}
2016-07-31 12:10:30 +02:00
} else if ( pragmaOnce . find ( header2 ) = = pragmaOnce . end ( ) ) {
includetokenstack . push ( gotoNextLine ( rawtok ) ) ;
2022-09-30 07:26:48 +02:00
const TokenList * const includetokens = filedata . find ( header2 ) - > second ;
2022-03-22 21:14:48 +01:00
rawtok = includetokens ? includetokens - > cfront ( ) : nullptr ;
2016-07-31 12:10:30 +02:00
continue ;
2016-07-20 12:21:00 +02:00
}
2018-05-14 13:00:22 +02:00
} else if ( rawtok - > str ( ) = = IF | | rawtok - > str ( ) = = IFDEF | | rawtok - > str ( ) = = IFNDEF | | rawtok - > str ( ) = = ELIF ) {
2016-07-31 12:10:30 +02:00
if ( ! sameline ( rawtok , rawtok - > next ) ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
simplecpp : : Output out ( files ) ;
out . type = Output : : SYNTAX_ERROR ;
out . location = rawtok - > location ;
2018-05-14 13:00:22 +02:00
out . msg = " Syntax error in # " + rawtok - > str ( ) ;
2016-07-31 12:10:30 +02:00
outputList - > push_back ( out ) ;
2016-12-06 14:10:57 +01:00
}
2016-07-31 12:10:30 +02:00
output . clear ( ) ;
return ;
}
2016-07-20 12:21:00 +02:00
bool conditionIsTrue ;
2023-04-05 21:17:48 +02:00
if ( ifstates . top ( ) = = AlwaysFalse | | ( ifstates . top ( ) = = ElseIsTrue & & rawtok - > str ( ) ! = ELIF ) )
2016-07-20 12:21:00 +02:00
conditionIsTrue = false ;
2022-03-22 21:14:48 +01:00
else if ( rawtok - > str ( ) = = IFDEF ) {
2021-04-26 16:25:39 +02:00
conditionIsTrue = ( macros . find ( rawtok - > next - > str ( ) ) ! = macros . end ( ) | | ( hasInclude & & rawtok - > next - > str ( ) = = HAS_INCLUDE ) ) ;
2022-03-22 21:14:48 +01:00
maybeUsedMacros [ rawtok - > next - > str ( ) ] . push_back ( rawtok - > next - > location ) ;
} else if ( rawtok - > str ( ) = = IFNDEF ) {
2021-04-26 16:25:39 +02:00
conditionIsTrue = ( macros . find ( rawtok - > next - > str ( ) ) = = macros . end ( ) & & ! ( hasInclude & & rawtok - > next - > str ( ) = = HAS_INCLUDE ) ) ;
2022-03-22 21:14:48 +01:00
maybeUsedMacros [ rawtok - > next - > str ( ) ] . push_back ( rawtok - > next - > location ) ;
} else { /*if (rawtok->str() == IF || rawtok->str() == ELIF)*/
2016-07-20 12:21:00 +02:00
TokenList expr ( files ) ;
for ( const Token * tok = rawtok - > next ; tok & & tok - > location . sameline ( rawtok - > location ) ; tok = tok - > next ) {
if ( ! tok - > name ) {
expr . push_back ( new Token ( * tok ) ) ;
continue ;
}
2018-05-14 13:00:22 +02:00
if ( tok - > str ( ) = = DEFINED ) {
2016-07-20 12:21:00 +02:00
tok = tok - > next ;
const bool par = ( tok & & tok - > op = = ' ( ' ) ;
if ( par )
tok = tok - > next ;
2022-03-22 21:14:48 +01:00
maybeUsedMacros [ rawtok - > next - > str ( ) ] . push_back ( rawtok - > next - > location ) ;
2016-11-10 20:04:05 +01:00
if ( tok ) {
2018-05-14 13:00:22 +02:00
if ( macros . find ( tok - > str ( ) ) ! = macros . end ( ) )
2016-11-10 20:04:05 +01:00
expr . push_back ( new Token ( " 1 " , tok - > location ) ) ;
2021-04-26 16:25:39 +02:00
else if ( hasInclude & & tok - > str ( ) = = HAS_INCLUDE )
expr . push_back ( new Token ( " 1 " , tok - > location ) ) ;
2016-11-10 20:04:05 +01:00
else
expr . push_back ( new Token ( " 0 " , tok - > location ) ) ;
}
if ( par )
2022-03-22 21:14:48 +01:00
tok = tok ? tok - > next : nullptr ;
2016-11-10 20:04:05 +01:00
if ( ! tok | | ! sameline ( rawtok , tok ) | | ( par & & tok - > op ! = ' ) ' ) ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
Output out ( rawtok - > location . files ) ;
out . type = Output : : SYNTAX_ERROR ;
out . location = rawtok - > location ;
2018-05-14 13:00:22 +02:00
out . msg = " failed to evaluate " + std : : string ( rawtok - > str ( ) = = IF ? " #if " : " #elif " ) + " condition " ;
2016-11-10 20:04:05 +01:00
outputList - > push_back ( out ) ;
2021-04-26 16:25:39 +02:00
}
output . clear ( ) ;
return ;
}
continue ;
}
if ( hasInclude & & tok - > str ( ) = = HAS_INCLUDE ) {
tok = tok - > next ;
const bool par = ( tok & & tok - > op = = ' ( ' ) ;
if ( par )
tok = tok - > next ;
2022-09-30 07:26:48 +02:00
bool closingAngularBracket = false ;
2021-04-26 16:25:39 +02:00
if ( tok ) {
const std : : string & sourcefile = rawtok - > location . file ( ) ;
2022-09-30 07:26:48 +02:00
const bool systemheader = ( tok & & tok - > op = = ' < ' ) ;
std : : string header ;
if ( systemheader ) {
while ( ( tok = tok - > next ) & & tok - > op ! = ' > ' )
header + = tok - > str ( ) ;
2023-09-13 10:30:42 +02:00
// cppcheck-suppress selfAssignment - platform-dependent implementation
2022-09-30 07:26:48 +02:00
header = realFilename ( header ) ;
if ( tok & & tok - > op = = ' > ' )
closingAngularBracket = true ;
}
else {
header = realFilename ( tok - > str ( ) . substr ( 1U , tok - > str ( ) . size ( ) - 2U ) ) ;
closingAngularBracket = true ;
}
2021-04-26 16:25:39 +02:00
std : : ifstream f ;
const std : : string header2 = openHeader ( f , dui , sourcefile , header , systemheader ) ;
expr . push_back ( new Token ( header2 . empty ( ) ? " 0 " : " 1 " , tok - > location ) ) ;
}
if ( par )
2022-03-22 21:14:48 +01:00
tok = tok ? tok - > next : nullptr ;
2022-09-30 07:26:48 +02:00
if ( ! tok | | ! sameline ( rawtok , tok ) | | ( par & & tok - > op ! = ' ) ' ) | | ( ! closingAngularBracket ) ) {
2021-04-26 16:25:39 +02:00
if ( outputList ) {
Output out ( rawtok - > location . files ) ;
out . type = Output : : SYNTAX_ERROR ;
out . location = rawtok - > location ;
out . msg = " failed to evaluate " + std : : string ( rawtok - > str ( ) = = IF ? " #if " : " #elif " ) + " condition " ;
outputList - > push_back ( out ) ;
2016-12-06 14:10:57 +01:00
}
2016-11-10 20:04:05 +01:00
output . clear ( ) ;
return ;
}
2016-07-20 12:21:00 +02:00
continue ;
}
2022-03-22 21:14:48 +01:00
maybeUsedMacros [ rawtok - > next - > str ( ) ] . push_back ( rawtok - > next - > location ) ;
2016-09-03 12:29:45 +02:00
const Token * tmp = tok ;
if ( ! preprocessToken ( expr , & tmp , macros , files , outputList ) ) {
output . clear ( ) ;
return ;
2016-07-20 12:21:00 +02:00
}
2019-07-03 17:03:46 +02:00
if ( ! tmp )
break ;
tok = tmp - > previous ;
2016-07-20 12:21:00 +02:00
}
try {
2021-07-21 20:29:00 +02:00
if ( ifCond ) {
std : : string E ;
for ( const simplecpp : : Token * tok = expr . cfront ( ) ; tok ; tok = tok - > next )
E + = ( E . empty ( ) ? " " : " " ) + tok - > str ( ) ;
2022-09-30 07:26:48 +02:00
const long long result = evaluate ( expr , dui , sizeOfType ) ;
2021-07-21 20:29:00 +02:00
conditionIsTrue = ( result ! = 0 ) ;
ifCond - > push_back ( IfCond ( rawtok - > location , E , result ) ) ;
} else {
2022-09-30 07:26:48 +02:00
const long long result = evaluate ( expr , dui , sizeOfType ) ;
2021-07-21 20:29:00 +02:00
conditionIsTrue = ( result ! = 0 ) ;
}
2017-08-21 18:43:42 +02:00
} catch ( const std : : exception & e ) {
2016-12-06 14:10:57 +01:00
if ( outputList ) {
Output out ( rawtok - > location . files ) ;
out . type = Output : : SYNTAX_ERROR ;
out . location = rawtok - > location ;
2018-05-14 13:00:22 +02:00
out . msg = " failed to evaluate " + std : : string ( rawtok - > str ( ) = = IF ? " #if " : " #elif " ) + " condition " ;
2017-08-21 18:43:42 +02:00
if ( e . what ( ) & & * e . what ( ) )
out . msg + = std : : string ( " , " ) + e . what ( ) ;
2016-07-20 12:21:00 +02:00
outputList - > push_back ( out ) ;
2016-12-06 14:10:57 +01:00
}
2016-07-21 19:42:26 +02:00
output . clear ( ) ;
return ;
2016-07-20 12:21:00 +02:00
}
}
2018-05-14 13:00:22 +02:00
if ( rawtok - > str ( ) ! = ELIF ) {
2016-07-20 12:21:00 +02:00
// push a new ifstate..
2023-04-05 21:17:48 +02:00
if ( ifstates . top ( ) ! = True )
ifstates . push ( AlwaysFalse ) ;
2016-07-20 12:21:00 +02:00
else
2023-04-05 21:17:48 +02:00
ifstates . push ( conditionIsTrue ? True : ElseIsTrue ) ;
} else if ( ifstates . top ( ) = = True ) {
ifstates . top ( ) = AlwaysFalse ;
} else if ( ifstates . top ( ) = = ElseIsTrue & & conditionIsTrue ) {
ifstates . top ( ) = True ;
2016-07-20 12:21:00 +02:00
}
2018-05-14 13:00:22 +02:00
} else if ( rawtok - > str ( ) = = ELSE ) {
2023-04-05 21:17:48 +02:00
ifstates . top ( ) = ( ifstates . top ( ) = = ElseIsTrue ) ? True : AlwaysFalse ;
2018-05-14 13:00:22 +02:00
} else if ( rawtok - > str ( ) = = ENDIF ) {
2016-12-04 12:10:28 +01:00
ifstates . pop ( ) ;
2018-05-14 13:00:22 +02:00
} else if ( rawtok - > str ( ) = = UNDEF ) {
2023-04-05 21:17:48 +02:00
if ( ifstates . top ( ) = = True ) {
2016-07-20 12:21:00 +02:00
const Token * tok = rawtok - > next ;
while ( sameline ( rawtok , tok ) & & tok - > comment )
tok = tok - > next ;
if ( sameline ( rawtok , tok ) )
2018-05-14 13:00:22 +02:00
macros . erase ( tok - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
}
2023-04-05 21:17:48 +02:00
} else if ( ifstates . top ( ) = = True & & rawtok - > str ( ) = = PRAGMA & & rawtok - > next & & rawtok - > next - > str ( ) = = ONCE & & sameline ( rawtok , rawtok - > next ) ) {
2016-07-21 12:47:00 +02:00
pragmaOnce . insert ( rawtok - > location . file ( ) ) ;
2016-07-20 12:21:00 +02:00
}
rawtok = gotoNextLine ( rawtok ) ;
continue ;
}
2023-04-05 21:17:48 +02:00
if ( ifstates . top ( ) ! = True ) {
2016-07-20 12:21:00 +02:00
// drop code
rawtok = gotoNextLine ( rawtok ) ;
continue ;
}
2016-07-25 09:13:59 +02:00
bool hash = false , hashhash = false ;
if ( rawtok - > op = = ' # ' & & sameline ( rawtok , rawtok - > next ) ) {
if ( rawtok - > next - > op ! = ' # ' ) {
hash = true ;
rawtok = rawtok - > next ; // skip '#'
} else if ( sameline ( rawtok , rawtok - > next - > next ) ) {
hashhash = true ;
rawtok = rawtok - > next - > next ; // skip '#' '#'
}
}
const Location loc ( rawtok - > location ) ;
TokenList tokens ( files ) ;
2016-09-03 12:29:45 +02:00
if ( ! preprocessToken ( tokens , & rawtok , macros , files , outputList ) ) {
output . clear ( ) ;
return ;
2016-07-25 09:13:59 +02:00
}
if ( hash | | hashhash ) {
std : : string s ;
2016-07-29 08:46:38 +02:00
for ( const Token * hashtok = tokens . cfront ( ) ; hashtok ; hashtok = hashtok - > next )
2018-05-14 13:00:22 +02:00
s + = hashtok - > str ( ) ;
2016-07-25 09:13:59 +02:00
if ( hash )
output . push_back ( new Token ( ' \" ' + s + ' \" ' , loc ) ) ;
2016-07-29 08:46:38 +02:00
else if ( output . back ( ) )
2018-05-14 13:00:22 +02:00
output . back ( ) - > setstr ( output . cback ( ) - > str ( ) + s ) ;
2016-07-25 09:13:59 +02:00
else
output . push_back ( new Token ( s , loc ) ) ;
} else {
output . takeTokens ( tokens ) ;
}
2016-07-20 12:21:00 +02:00
}
if ( macroUsage ) {
2022-03-22 21:14:48 +01:00
for ( simplecpp : : MacroMap : : const_iterator macroIt = macros . begin ( ) ; macroIt ! = macros . end ( ) ; + + macroIt ) {
2016-07-20 12:21:00 +02:00
const Macro & macro = macroIt - > second ;
2022-03-22 21:14:48 +01:00
std : : list < Location > usage = macro . usage ( ) ;
const std : : list < Location > & temp = maybeUsedMacros [ macro . name ( ) ] ;
usage . insert ( usage . end ( ) , temp . begin ( ) , temp . end ( ) ) ;
2016-07-20 12:21:00 +02:00
for ( std : : list < Location > : : const_iterator usageIt = usage . begin ( ) ; usageIt ! = usage . end ( ) ; + + usageIt ) {
2018-09-26 12:17:14 +02:00
MacroUsage mu ( usageIt - > files , macro . valueDefinedInCode ( ) ) ;
2016-07-20 12:21:00 +02:00
mu . macroName = macro . name ( ) ;
mu . macroLocation = macro . defineLocation ( ) ;
mu . useLocation = * usageIt ;
macroUsage - > push_back ( mu ) ;
}
}
}
}
2016-07-31 20:48:55 +02:00
2016-12-06 14:10:57 +01:00
void simplecpp : : cleanup ( std : : map < std : : string , TokenList * > & filedata )
{
2016-07-31 20:48:55 +02:00
for ( std : : map < std : : string , TokenList * > : : iterator it = filedata . begin ( ) ; it ! = filedata . end ( ) ; + + it )
delete it - > second ;
filedata . clear ( ) ;
}
2022-03-22 21:14:48 +01:00
std : : string simplecpp : : getCStdString ( const std : : string & std )
{
if ( std = = " c90 " | | std = = " c89 " | | std = = " iso9899:1990 " | | std = = " iso9899:199409 " | | std = = " gnu90 " | | std = = " gnu89 " ) {
// __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments
return " " ;
}
if ( std = = " c99 " | | std = = " c9x " | | std = = " iso9899:1999 " | | std = = " iso9899:199x " | | std = = " gnu99 " | | std = = " gnu9x " )
return " 199901L " ;
if ( std = = " c11 " | | std = = " c1x " | | std = = " iso9899:2011 " | | std = = " gnu11 " | | std = = " gnu1x " )
return " 201112L " ;
if ( std = = " c17 " | | std = = " c18 " | | std = = " iso9899:2017 " | | std = = " iso9899:2018 " | | std = = " gnu17 " | | std = = " gnu18 " )
return " 201710L " ;
2023-09-13 10:30:42 +02:00
if ( std = = " c23 " | | std = = " gnu23 " | | std = = " c2x " | | std = = " gnu2x " ) {
// supported by GCC 9+ and Clang 9+
// Clang 9, 10, 11, 12, 13 return "201710L"
// Clang 14, 15, 16, 17 return "202000L"
// Clang 9, 10, 11, 12, 13, 14, 15, 16, 17 do not support "c23" and "gnu23"
return " 202311L " ;
2022-03-22 21:14:48 +01:00
}
return " " ;
}
std : : string simplecpp : : getCppStdString ( const std : : string & std )
{
if ( std = = " c++98 " | | std = = " c++03 " | | std = = " gnu++98 " | | std = = " gnu++03 " )
return " 199711L " ;
if ( std = = " c++11 " | | std = = " gnu++11 " | | std = = " c++0x " | | std = = " gnu++0x " )
return " 201103L " ;
if ( std = = " c++14 " | | std = = " c++1y " | | std = = " gnu++14 " | | std = = " gnu++1y " )
return " 201402L " ;
if ( std = = " c++17 " | | std = = " c++1z " | | std = = " gnu++17 " | | std = = " gnu++1z " )
return " 201703L " ;
if ( std = = " c++20 " | | std = = " c++2a " | | std = = " gnu++20 " | | std = = " gnu++2a " ) {
2022-04-14 18:13:13 +02:00
// GCC 10 returns "201703L" - correct in 11+
2022-03-22 21:14:48 +01:00
return " 202002L " ;
}
if ( std = = " c++23 " | | std = = " c++2b " | | std = = " gnu++23 " | | std = = " gnu++2b " ) {
2022-04-14 18:13:13 +02:00
// supported by GCC 11+ and Clang 12+
2023-09-13 10:30:42 +02:00
// GCC 11, 12, 13 return "202100L"
// Clang 12, 13, 14, 15, 16 do not support "c++23" and "gnu++23" and return "202101L"
// Clang 17, 18 return "202302L"
return " 202302L " ;
}
if ( std = = " c++26 " | | std = = " c++2c " | | std = = " gnu++26 " | | std = = " gnu++2c " ) {
// supported by Clang 17+
return " 202400L " ;
2022-04-14 18:13:13 +02:00
}
2022-03-22 21:14:48 +01:00
return " " ;
}
# if (__cplusplus < 201103L) && !defined(__APPLE__)
# undef nullptr
# endif