2016-07-20 12:21:00 +02:00
/*
* simplecpp - A simple and high - fidelity C / C + + preprocessor library
* Copyright ( C ) 2016 Daniel Marjamäki .
*
* 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/>.
*/
# include "simplecpp.h"
# include <algorithm>
# include <cctype>
2016-07-21 15:05:29 +02:00
# include <limits>
2016-07-20 12:21:00 +02:00
# include <list>
# include <map>
# include <set>
# include <stdexcept>
# include <vector>
# include <cstring>
2016-07-21 15:13:27 +02:00
# include <cstdlib> // strtoll, etc
2016-07-20 12:21:00 +02:00
# include <sstream>
# include <fstream>
# include <iostream>
# include <stack>
namespace {
const simplecpp : : TokenString DEFINE ( " define " ) ;
const simplecpp : : TokenString UNDEF ( " undef " ) ;
const simplecpp : : TokenString INCLUDE ( " include " ) ;
const simplecpp : : TokenString ERROR ( " error " ) ;
const simplecpp : : TokenString WARNING ( " warning " ) ;
const simplecpp : : TokenString IF ( " if " ) ;
const simplecpp : : TokenString IFDEF ( " ifdef " ) ;
const simplecpp : : TokenString IFNDEF ( " ifndef " ) ;
const simplecpp : : TokenString DEFINED ( " defined " ) ;
const simplecpp : : TokenString ELSE ( " else " ) ;
const simplecpp : : TokenString ELIF ( " elif " ) ;
const simplecpp : : TokenString ENDIF ( " endif " ) ;
2016-07-21 12:47:00 +02:00
const simplecpp : : TokenString PRAGMA ( " pragma " ) ;
const simplecpp : : TokenString ONCE ( " once " ) ;
2016-07-20 20:03:27 +02:00
template < class T > std : : string toString ( T t ) {
std : : ostringstream ostr ;
ostr < < t ;
return ostr . str ( ) ;
}
2016-07-21 15:59:59 +02:00
long long stringToLL ( const std : : string & s )
{
long long ret ;
bool hex = ( s . compare ( 0 , 2 , " 0x " ) = = 0 ) ;
std : : istringstream istr ( hex ? s . substr ( 2 ) : s ) ;
if ( hex )
istr > > std : : hex ;
istr > > ret ;
return ret ;
}
unsigned long long stringToULL ( const std : : string & s )
{
unsigned long long ret ;
bool hex = ( s . compare ( 0 , 2 , " 0x " ) = = 0 ) ;
std : : istringstream istr ( hex ? s . substr ( 2 ) : s ) ;
if ( hex )
istr > > std : : hex ;
istr > > ret ;
return ret ;
}
2016-07-28 09:26:23 +02:00
bool endsWith ( const std : : string & s , const std : : string & e ) {
return ( s . size ( ) > = e . size ( ) & & s . compare ( s . size ( ) - e . size ( ) , e . size ( ) , e ) = = 0 ) ;
}
2016-07-21 15:59:59 +02:00
2016-07-20 12:21:00 +02:00
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
static bool isAlternativeBinaryOp ( const simplecpp : : Token * tok , const std : : string & alt ) {
return ( tok - > name & &
tok - > str = = alt & &
tok - > previous & &
tok - > next & &
( tok - > previous - > number | | tok - > previous - > name | | tok - > previous - > op = = ' ) ' ) & &
( tok - > next - > number | | tok - > next - > name | | tok - > next - > op = = ' ( ' ) ) ;
}
static bool isAlternativeUnaryOp ( const simplecpp : : Token * tok , const std : : string & alt ) {
return ( ( tok - > name & & tok - > str = = alt ) & &
( ! tok - > previous | | tok - > previous - > op = = ' ( ' ) & &
( tok - > next & & ( tok - > next - > name | | tok - > next - > number ) ) ) ;
}
2016-07-20 12:21:00 +02:00
}
void simplecpp : : Location : : adjust ( const std : : string & str ) {
if ( str . find_first_of ( " \r \n " ) = = std : : string : : npos ) {
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 ' ) {
col = 0 ;
line + + ;
if ( str [ i ] = = ' \r ' & & ( i + 1 ) < str . size ( ) & & str [ i + 1 ] = = ' \n ' )
+ + i ;
}
}
}
bool simplecpp : : Token : : isOneOf ( const char ops [ ] ) const {
return ( op ! = ' \0 ' ) & & ( std : : strchr ( ops , op ) ! = 0 ) ;
}
bool simplecpp : : Token : : startsWithOneOf ( const char c [ ] ) const {
return std : : strchr ( c , str [ 0 ] ) ! = 0 ;
}
bool simplecpp : : Token : : endsWithOneOf ( const char c [ ] ) const {
return std : : strchr ( c , str [ str . size ( ) - 1U ] ) ! = 0 ;
}
2016-07-25 09:13:59 +02:00
void simplecpp : : Token : : printAll ( ) const {
const Token * tok = this ;
while ( tok - > previous )
tok = tok - > previous ;
for ( const Token * tok = this ; tok ; tok = tok - > next ) {
if ( tok - > previous ) {
std : : cout < < ( sameline ( tok , tok - > previous ) ? ' ' : ' \n ' ) ;
}
std : : cout < < tok - > str ;
}
std : : cout < < std : : endl ;
}
void simplecpp : : Token : : printOut ( ) const {
for ( const Token * tok = this ; tok ; tok = tok - > next ) {
if ( tok ! = this ) {
std : : cout < < ( sameline ( tok , tok - > previous ) ? ' ' : ' \n ' ) ;
}
std : : cout < < tok - > str ;
}
std : : cout < < std : : endl ;
}
2016-07-29 08:46:38 +02:00
simplecpp : : TokenList : : TokenList ( std : : vector < std : : string > & filenames ) : frontToken ( NULL ) , backToken ( NULL ) , 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 )
2016-07-29 08:46:38 +02:00
: frontToken ( NULL ) , backToken ( NULL ) , files ( filenames ) {
2016-07-20 12:21:00 +02:00
readfile ( istr , filename , outputList ) ;
}
2016-07-29 08:46:38 +02:00
simplecpp : : TokenList : : TokenList ( const TokenList & other ) : frontToken ( NULL ) , backToken ( NULL ) , files ( other . files ) {
2016-07-20 12:21:00 +02:00
* this = other ;
}
simplecpp : : TokenList : : ~ TokenList ( ) {
clear ( ) ;
}
void simplecpp : : TokenList : : operator = ( const TokenList & other ) {
if ( this = = & other )
return ;
clear ( ) ;
2016-07-29 08:46:38 +02:00
for ( const Token * tok = other . cfront ( ) ; tok ; tok = tok - > next )
2016-07-20 12:21:00 +02:00
push_back ( new Token ( * tok ) ) ;
2016-07-20 15:04:03 +02:00
sizeOfType = other . sizeOfType ;
2016-07-20 12:21:00 +02:00
}
void simplecpp : : TokenList : : clear ( ) {
2016-07-29 08:46:38 +02:00
backToken = NULL ;
while ( frontToken ) {
Token * next = frontToken - > next ;
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
}
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
}
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
}
std : : string simplecpp : : TokenList : : stringify ( ) const {
std : : ostringstream ret ;
Location loc ( files ) ;
2016-07-29 08:46:38 +02:00
for ( const Token * tok = cfront ( ) ; tok ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
while ( tok - > location . line > loc . line ) {
ret < < ' \n ' ;
loc . line + + ;
}
if ( sameline ( tok - > previous , tok ) )
ret < < ' ' ;
ret < < tok - > str ;
loc . adjust ( tok - > str ) ;
}
return ret . str ( ) ;
}
static unsigned char readChar ( std : : istream & istr , unsigned int bom )
{
unsigned char ch = ( unsigned char ) istr . get ( ) ;
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
// character is non-ASCII character then replace it with 0xff
if ( bom = = 0xfeff | | bom = = 0xfffe ) {
const unsigned char ch2 = ( unsigned char ) istr . get ( ) ;
const int ch16 = ( bom = = 0xfeff ) ? ( ch < < 8 | ch2 ) : ( ch2 < < 8 | ch ) ;
ch = ( unsigned char ) ( ( ch16 > = 0x80 ) ? 0xff : ch16 ) ;
}
// Handling of newlines..
if ( ch = = ' \r ' ) {
ch = ' \n ' ;
if ( bom = = 0 & & ( char ) istr . peek ( ) = = ' \n ' )
( void ) istr . get ( ) ;
else if ( bom = = 0xfeff | | bom = = 0xfffe ) {
int c1 = istr . get ( ) ;
int c2 = istr . get ( ) ;
int ch16 = ( bom = = 0xfeff ) ? ( c1 < < 8 | c2 ) : ( c2 < < 8 | c1 ) ;
if ( ch16 ! = ' \n ' ) {
istr . unget ( ) ;
istr . unget ( ) ;
}
}
}
return ch ;
}
static unsigned char peekChar ( std : : istream & istr , unsigned int bom ) {
unsigned char ch = ( unsigned char ) istr . peek ( ) ;
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
// character is non-ASCII character then replace it with 0xff
if ( bom = = 0xfeff | | bom = = 0xfffe ) {
const unsigned char ch2 = ( unsigned char ) istr . peek ( ) ;
const int ch16 = ( bom = = 0xfeff ) ? ( ch < < 8 | ch2 ) : ( ch2 < < 8 | ch ) ;
ch = ( unsigned char ) ( ( ch16 > = 0x80 ) ? 0xff : ch16 ) ;
}
// Handling of newlines..
if ( ch = = ' \r ' ) {
ch = ' \n ' ;
if ( bom ! = 0 )
( void ) istr . peek ( ) ;
}
return ch ;
}
2016-07-28 09:26:23 +02:00
static void ungetChar ( std : : istream & istr , unsigned int bom ) {
istr . unget ( ) ;
if ( bom ! = 0 )
istr . unget ( ) ;
}
2016-07-20 12:21:00 +02:00
static unsigned short getAndSkipBOM ( std : : istream & istr ) {
const unsigned char ch1 = istr . peek ( ) ;
// The UTF-16 BOM is 0xfffe or 0xfeff.
if ( ch1 > = 0xfe ) {
unsigned short bom = ( ( unsigned char ) istr . get ( ) < < 8 ) ;
if ( istr . peek ( ) > = 0xfe )
return bom | ( unsigned char ) istr . get ( ) ;
return 0 ;
}
if ( ch1 = = 0xef & & istr . peek ( ) = = 0xbb & & istr . peek ( ) = = 0xbf ) {
// Skip BOM 0xefbbbf
( void ) istr . get ( ) ;
( void ) istr . get ( ) ;
( void ) istr . get ( ) ;
}
return 0 ;
}
2016-07-29 13:05:35 +02:00
bool isNameChar ( unsigned char ch ) {
return std : : isalnum ( ch ) | | ch = = ' _ ' | | ch = = ' $ ' ;
2016-07-29 20:54:11 +02:00
}
2016-07-29 13:05:35 +02:00
2016-07-20 12:21:00 +02:00
void simplecpp : : TokenList : : readfile ( std : : istream & istr , const std : : string & filename , OutputList * outputList )
{
std : : stack < simplecpp : : Location > loc ;
unsigned int multiline = 0U ;
2016-07-21 15:05:29 +02:00
const Token * oldLastToken = NULL ;
2016-07-20 12:21:00 +02:00
const unsigned short bom = getAndSkipBOM ( istr ) ;
Location location ( files ) ;
location . fileIndex = fileIndex ( filename ) ;
location . line = 1U ;
2016-07-30 10:37:55 +02:00
location . col = 1U ;
2016-07-20 12:21:00 +02:00
while ( istr . good ( ) ) {
unsigned char ch = readChar ( istr , bom ) ;
if ( ! istr . good ( ) )
break ;
if ( ch = = ' \n ' ) {
2016-07-29 08:46:38 +02:00
if ( cback ( ) & & cback ( ) - > op = = ' \\ ' ) {
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-07-30 10:37:55 +02:00
location . col = 1 ;
2016-07-20 12:21:00 +02:00
2016-07-29 08:46:38 +02:00
if ( oldLastToken ! = cback ( ) ) {
oldLastToken = cback ( ) ;
2016-07-20 12:21:00 +02:00
const std : : string lastline ( lastLine ( ) ) ;
if ( lastline = = " # file %str% " ) {
loc . push ( location ) ;
2016-07-29 08:46:38 +02:00
location . fileIndex = fileIndex ( cback ( ) - > str . substr ( 1U , cback ( ) - > str . size ( ) - 2U ) ) ;
2016-07-20 12:21:00 +02:00
location . line = 1U ;
}
// #endfile
else if ( lastline = = " # endfile " & & ! loc . empty ( ) ) {
location = loc . top ( ) ;
loc . pop ( ) ;
}
}
continue ;
}
2016-07-30 10:37:55 +02:00
if ( std : : isspace ( ch ) ) {
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 ;
// number or name
2016-07-29 13:05:35 +02:00
if ( isNameChar ( ch ) ) {
while ( istr . good ( ) & & isNameChar ( ch ) ) {
2016-07-20 12:21:00 +02:00
currentToken + = ch ;
ch = readChar ( istr , bom ) ;
}
2016-07-28 09:26:23 +02:00
ungetChar ( istr , bom ) ;
2016-07-20 12:21:00 +02:00
}
// comment
else if ( ch = = ' / ' & & peekChar ( istr , bom ) = = ' / ' ) {
while ( istr . good ( ) & & ch ! = ' \r ' & & ch ! = ' \n ' ) {
currentToken + = ch ;
ch = readChar ( istr , bom ) ;
}
if ( currentToken [ currentToken . size ( ) - 1U ] = = ' \\ ' ) {
2016-07-30 10:37:55 +02:00
+ + multiline ;
currentToken . erase ( currentToken . size ( ) - 1U ) ;
2016-07-20 12:21:00 +02:00
} else {
istr . unget ( ) ;
}
}
// comment
else if ( ch = = ' / ' & & peekChar ( istr , bom ) = = ' * ' ) {
currentToken = " /* " ;
( void ) readChar ( istr , bom ) ;
ch = readChar ( istr , bom ) ;
while ( istr . good ( ) ) {
currentToken + = ch ;
2016-07-30 10:37:55 +02:00
if ( currentToken . size ( ) > = 4U & & endsWith ( currentToken , " */ " ) )
2016-07-20 12:21:00 +02:00
break ;
ch = readChar ( istr , bom ) ;
}
2016-07-30 10:37:55 +02:00
// multiline..
std : : string : : size_type pos = 0 ;
while ( ( pos = currentToken . find ( " \\ \n " , pos ) ) ! = std : : string : : npos ) {
currentToken . erase ( pos , 2 ) ;
+ + multiline ;
}
2016-07-20 12:21:00 +02:00
}
// string / char literal
else if ( ch = = ' \" ' | | ch = = ' \' ' ) {
2016-07-28 09:26:23 +02:00
// C++11 raw string literal
2016-07-29 08:46:38 +02:00
if ( ch = = ' \" ' & & cback ( ) & & cback ( ) - > op = = ' R ' ) {
2016-07-28 09:26:23 +02:00
std : : string delim ;
ch = readChar ( istr , bom ) ;
while ( istr . good ( ) & & ch ! = ' ( ' & & ch ! = ' \" ' & & ch ! = ' \n ' ) {
delim + = ch ;
ch = readChar ( istr , bom ) ;
}
if ( ! istr . good ( ) | | ch = = ' \" ' | | ch = = ' \n ' )
// TODO report
return ;
currentToken = ' \" ' ;
const std : : string endOfRawString ( ' ) ' + delim + ' \" ' ) ;
while ( istr . good ( ) & & ! endsWith ( currentToken , endOfRawString ) )
currentToken + = readChar ( istr , bom ) ;
if ( ! endsWith ( currentToken , endOfRawString ) )
// TODO report
return ;
currentToken . erase ( currentToken . size ( ) - endOfRawString . size ( ) , endOfRawString . size ( ) - 1U ) ;
2016-07-29 08:46:38 +02:00
back ( ) - > setstr ( currentToken ) ;
2016-07-28 09:26:23 +02:00
location . col + = currentToken . size ( ) + 2U + 2 * delim . size ( ) ;
continue ;
}
2016-07-20 12:21:00 +02:00
currentToken = readUntil ( istr , location , ch , ch , outputList ) ;
if ( currentToken . size ( ) < 2U )
2016-07-28 09:26:23 +02:00
// TODO report
2016-07-20 12:21:00 +02:00
return ;
}
else {
currentToken + = ch ;
}
if ( currentToken = = " < " & & lastLine ( ) = = " # include " ) {
currentToken = readUntil ( istr , location , ' < ' , ' > ' , outputList ) ;
if ( currentToken . size ( ) < 2U )
return ;
}
push_back ( new Token ( currentToken , location ) ) ;
location . adjust ( currentToken ) ;
}
combineOperators ( ) ;
}
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 ) ;
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 ) ;
}
}
void simplecpp : : TokenList : : combineOperators ( ) {
2016-07-29 08:46:38 +02:00
for ( Token * tok = front ( ) ; tok ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
if ( tok - > op = = ' . ' ) {
// float literals..
if ( tok - > previous & & tok - > previous - > number ) {
tok - > setstr ( tok - > previous - > str + ' . ' ) ;
deleteToken ( tok - > previous ) ;
if ( tok - > next & & tok - > next - > startsWithOneOf ( " Ee " ) ) {
tok - > setstr ( tok - > str + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
}
}
if ( tok - > next & & tok - > next - > number ) {
tok - > setstr ( tok - > str + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
}
}
// match: [0-9.]+E [+-] [0-9]+
2016-07-21 15:05:29 +02:00
const char lastChar = tok - > str [ tok - > str . size ( ) - 1 ] ;
if ( tok - > number & & ( lastChar = = ' E ' | | lastChar = = ' e ' ) & & tok - > next & & tok - > next - > isOneOf ( " +- " ) & & tok - > next - > next & & tok - > next - > next - > number ) {
2016-07-20 12:21:00 +02:00
tok - > setstr ( tok - > str + tok - > next - > op + tok - > next - > next - > str ) ;
deleteToken ( tok - > next ) ;
deleteToken ( tok - > next ) ;
}
if ( tok - > op = = ' \0 ' | | ! tok - > next | | tok - > next - > op = = ' \0 ' )
continue ;
if ( tok - > next - > op = = ' = ' & & tok - > isOneOf ( " =!<>+-*/%&|^ " ) ) {
tok - > setstr ( tok - > str + " = " ) ;
deleteToken ( tok - > next ) ;
} else if ( ( tok - > op = = ' | ' | | tok - > op = = ' & ' ) & & tok - > op = = tok - > next - > op ) {
tok - > setstr ( tok - > str + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
} else if ( tok - > op = = ' : ' & & tok - > next - > op = = ' : ' ) {
tok - > setstr ( tok - > str + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
} else if ( tok - > op = = ' - ' & & tok - > next - > op = = ' > ' ) {
tok - > setstr ( tok - > str + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
} else if ( ( tok - > op = = ' < ' | | tok - > op = = ' > ' ) & & tok - > op = = tok - > next - > op ) {
tok - > setstr ( tok - > str + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
if ( tok - > next & & tok - > next - > op = = ' = ' ) {
tok - > setstr ( tok - > str + tok - > next - > str ) ;
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 ;
tok - > setstr ( tok - > str + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
}
}
}
void simplecpp : : TokenList : : constFoldUnaryNotPosNeg ( simplecpp : : Token * tok ) {
2016-07-31 20:48:55 +02:00
const std : : string NOT ( " not " ) ;
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 = ' ! ' ;
2016-07-20 12:21:00 +02:00
if ( tok - > op = = ' ! ' & & tok - > next & & tok - > next - > number ) {
tok - > setstr ( tok - > next - > str = = " 0 " ? " 1 " : " 0 " ) ;
deleteToken ( tok - > next ) ;
}
else {
if ( tok - > previous & & ( tok - > previous - > number | | tok - > previous - > name ) )
continue ;
if ( ! tok - > next | | ! tok - > next - > number )
continue ;
switch ( tok - > op ) {
case ' + ' :
tok - > setstr ( tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
break ;
case ' - ' :
tok - > setstr ( tok - > op + tok - > next - > str ) ;
deleteToken ( tok - > next ) ;
break ;
}
}
}
}
void simplecpp : : TokenList : : constFoldMulDivRem ( 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 ;
if ( tok - > op = = ' * ' )
2016-07-21 15:59:59 +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 = = ' % ' ) {
2016-07-21 15:59:59 +02:00
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 " ) ;
2016-07-21 15:59:59 +02:00
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-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 ) ;
}
}
void simplecpp : : TokenList : : constFoldAddSub ( 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 ;
if ( tok - > op = = ' + ' )
2016-07-21 15:59:59 +02:00
result = stringToLL ( tok - > previous - > str ) + stringToLL ( tok - > next - > str ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > op = = ' - ' )
2016-07-21 15:59:59 +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 ) ;
}
}
void simplecpp : : TokenList : : constFoldComparison ( Token * tok ) {
2016-07-31 20:48:55 +02:00
const std : : string NOTEQ ( " not_eq " ) ;
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 ;
if ( tok - > str = = " == " )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) = = stringToLL ( tok - > next - > str ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > str = = " != " )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) ! = stringToLL ( tok - > next - > str ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > str = = " > " )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) > stringToLL ( tok - > next - > str ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > str = = " >= " )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) > = stringToLL ( tok - > next - > str ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > str = = " < " )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) < stringToLL ( tok - > next - > str ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > str = = " <= " )
2016-07-21 15:59:59 +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 ) ;
}
}
void simplecpp : : TokenList : : constFoldBitwise ( Token * tok )
{
Token * const tok1 = tok ;
for ( const char * op = " &^| " ; * op ; op + + ) {
2016-07-23 09:26:06 +02:00
std : : string altop ;
if ( * op = = ' & ' )
altop = " bitand " ;
else if ( * op = = ' | ' )
altop = " bitor " ;
else
altop = " xor " ;
2016-07-20 12:21:00 +02:00
for ( tok = tok1 ; tok & & tok - > op ! = ' ) ' ; tok = tok - > next ) {
2016-07-31 20:48:55 +02:00
if ( tok - > op ! = * op & & ! isAlternativeBinaryOp ( tok , altop ) )
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 = = ' & ' )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) & stringToLL ( tok - > next - > str ) ) ;
2016-07-23 09:26:06 +02:00
else if ( * op = = ' ^ ' )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) ^ stringToLL ( tok - > next - > str ) ) ;
2016-07-23 09:26:06 +02:00
else /*if (*op == '|')*/
2016-07-21 15:59:59 +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 ) ;
}
}
}
void simplecpp : : TokenList : : constFoldLogicalOp ( Token * tok ) {
2016-07-31 20:48:55 +02:00
const std : : string AND ( " and " ) ;
const std : : string OR ( " or " ) ;
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 ( " || " ) ;
}
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 ;
2016-07-31 20:48:55 +02:00
if ( tok - > str = = " || " )
2016-07-21 15:59:59 +02:00
result = ( stringToLL ( tok - > previous - > str ) | | stringToLL ( tok - > next - > str ) ) ;
2016-07-20 12:21:00 +02:00
else /*if (tok->str == "&&")*/
2016-07-21 15:59:59 +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 ) ;
}
}
void simplecpp : : TokenList : : constFoldQuestionOp ( Token * * tok1 ) {
bool gotoTok1 = false ;
for ( Token * tok = * tok1 ; tok & & tok - > op ! = ' ) ' ; tok = gotoTok1 ? * tok1 : tok - > next ) {
gotoTok1 = false ;
if ( tok - > str ! = " ? " )
continue ;
if ( ! tok - > previous | | ! tok - > previous - > number )
continue ;
if ( ! tok - > next )
continue ;
if ( ! tok - > next - > next | | tok - > next - > next - > op ! = ' : ' )
continue ;
Token * const condTok = tok - > previous ;
Token * const trueTok = tok - > next ;
Token * const falseTok = trueTok - > next - > next ;
if ( condTok = = * tok1 )
* tok1 = ( condTok - > str ! = " 0 " ? trueTok : falseTok ) ;
deleteToken ( condTok - > next ) ; // ?
deleteToken ( trueTok - > next ) ; // :
deleteToken ( condTok - > str = = " 0 " ? trueTok : falseTok ) ;
deleteToken ( condTok ) ;
gotoTok1 = true ;
}
}
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 ) {
Token * tok1 = tok ;
tok = tok - > next ;
if ( tok1 - > comment )
deleteToken ( tok1 ) ;
}
}
std : : string simplecpp : : TokenList : : readUntil ( std : : istream & istr , const Location & location , const char start , const char end , OutputList * outputList ) {
std : : string ret ;
ret + = start ;
char ch = 0 ;
while ( ch ! = end & & ch ! = ' \r ' & & ch ! = ' \n ' & & istr . good ( ) ) {
ch = ( unsigned char ) istr . get ( ) ;
ret + = ch ;
if ( ch = = ' \\ ' )
ret + = ( unsigned char ) istr . get ( ) ;
}
if ( ! istr . good ( ) | | ch ! = end ) {
clear ( ) ;
if ( outputList ) {
Output err ( files ) ;
err . type = Output : : ERROR ;
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-07-28 09:26:23 +02: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 ;
2016-07-29 08:46:38 +02:00
for ( const Token * tok = cback ( ) ; sameline ( tok , cback ( ) ) ; tok = tok - > previous ) {
2016-07-20 12:21:00 +02:00
if ( tok - > comment )
continue ;
if ( ! ret . empty ( ) )
ret = ' ' + ret ;
ret = ( tok - > str [ 0 ] = = ' \" ' ? std : : string ( " %str% " ) : tok - > str ) + ret ;
2016-07-28 09:26:23 +02:00
if ( + + count > maxsize )
return " " ;
2016-07-20 12:21:00 +02:00
}
return ret ;
}
unsigned int simplecpp : : TokenList : : fileIndex ( const std : : string & filename ) {
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 {
class Macro {
public :
2016-07-28 09:26:23 +02:00
explicit Macro ( std : : vector < std : : string > & f ) : nameToken ( NULL ) , variadic ( false ) , valueToken ( NULL ) , endToken ( NULL ) , files ( f ) , tokenListDefine ( f ) { }
2016-07-20 12:21:00 +02:00
2016-07-28 09:26:23 +02:00
Macro ( const Token * tok , std : : vector < std : : string > & f ) : nameToken ( NULL ) , files ( f ) , tokenListDefine ( f ) {
2016-07-20 12:21:00 +02:00
if ( sameline ( tok - > previous , tok ) )
throw std : : runtime_error ( " bad macro syntax " ) ;
if ( tok - > op ! = ' # ' )
throw std : : runtime_error ( " bad macro syntax " ) ;
tok = tok - > next ;
if ( ! tok | | tok - > str ! = DEFINE )
throw std : : runtime_error ( " bad macro syntax " ) ;
tok = tok - > next ;
if ( ! tok | | ! tok - > name )
throw std : : runtime_error ( " bad macro syntax " ) ;
parseDefine ( tok ) ;
}
2016-07-28 09:26:23 +02:00
Macro ( const std : : string & name , const std : : string & value , std : : vector < std : : string > & f ) : nameToken ( NULL ) , files ( f ) , tokenListDefine ( f ) {
2016-07-20 12:21:00 +02:00
const std : : string def ( name + ' ' + value ) ;
std : : istringstream istr ( def ) ;
tokenListDefine . readfile ( istr ) ;
2016-07-29 08:46:38 +02:00
parseDefine ( tokenListDefine . cfront ( ) ) ;
2016-07-20 12:21:00 +02:00
}
2016-07-21 15:05:29 +02:00
Macro ( const Macro & macro ) : nameToken ( NULL ) , files ( macro . files ) , tokenListDefine ( macro . files ) {
2016-07-20 12:21:00 +02:00
* this = macro ;
}
void operator = ( const Macro & macro ) {
if ( this ! = & macro ) {
if ( macro . tokenListDefine . empty ( ) )
parseDefine ( macro . nameToken ) ;
else {
tokenListDefine = macro . tokenListDefine ;
2016-07-29 08:46:38 +02:00
parseDefine ( tokenListDefine . cfront ( ) ) ;
2016-07-20 12:21:00 +02:00
}
}
}
2016-07-23 16:26:11 +02:00
const Token * expand ( TokenList * const output ,
const Token * rawtok ,
const std : : map < TokenString , Macro > & macros ,
std : : vector < std : : string > & files ) const {
std : : set < TokenString > expandedmacros ;
TokenList output2 ( files ) ;
2016-07-24 08:22:49 +02:00
rawtok = expand ( & output2 , rawtok - > location , rawtok , macros , expandedmacros ) ;
2016-07-29 08:46:38 +02:00
while ( output2 . cback ( ) & & rawtok ) {
2016-07-24 08:22:49 +02:00
unsigned int par = 0 ;
2016-07-29 08:46:38 +02:00
Token * macro2tok = output2 . back ( ) ;
2016-07-24 08:22:49 +02:00
while ( macro2tok ) {
if ( macro2tok - > op = = ' ( ' ) {
if ( par = = 0 )
break ;
- - par ;
}
else if ( macro2tok - > op = = ' ) ' )
+ + par ;
2016-07-23 16:26:11 +02:00
macro2tok = macro2tok - > previous ;
2016-07-24 08:22:49 +02:00
}
if ( macro2tok ) { // macro2tok->op == '('
macro2tok = macro2tok - > previous ;
expandedmacros . insert ( name ( ) ) ;
}
else if ( rawtok - > op = = ' ( ' )
2016-07-29 08:46:38 +02:00
macro2tok = output2 . back ( ) ;
2016-07-23 16:26:11 +02:00
if ( ! macro2tok | | ! macro2tok - > name )
break ;
2016-07-29 08:46:38 +02:00
if ( output2 . cfront ( ) ! = output2 . cback ( ) & & macro2tok - > str = = this - > name ( ) )
2016-07-23 16:26:11 +02:00
break ;
const std : : map < TokenString , Macro > : : const_iterator macro = macros . find ( macro2tok - > str ) ;
if ( macro = = macros . end ( ) | | ! macro - > second . functionLike ( ) )
break ;
TokenList rawtokens2 ( files ) ;
2016-07-24 08:22:49 +02:00
const Location loc ( macro2tok - > location ) ;
2016-07-23 16:26:11 +02:00
while ( macro2tok ) {
Token * next = macro2tok - > next ;
2016-07-24 08:22:49 +02:00
rawtokens2 . push_back ( new Token ( macro2tok - > str , loc ) ) ;
2016-07-23 16:26:11 +02:00
output2 . deleteToken ( macro2tok ) ;
macro2tok = next ;
}
2016-07-29 08:46:38 +02:00
par = ( rawtokens2 . cfront ( ) ! = rawtokens2 . cback ( ) ) ? 1U : 0U ;
2016-07-23 16:26:11 +02:00
const Token * rawtok2 = rawtok ;
for ( ; rawtok2 ; rawtok2 = rawtok2 - > next ) {
2016-07-24 08:22:49 +02:00
rawtokens2 . push_back ( new Token ( rawtok2 - > str , loc ) ) ;
2016-07-23 16:26:11 +02:00
if ( rawtok2 - > op = = ' ( ' )
+ + par ;
else if ( rawtok2 - > op = = ' ) ' ) {
if ( par < = 1U )
break ;
- - par ;
}
}
if ( ! rawtok2 | | par ! = 1U )
break ;
2016-07-29 08:46:38 +02:00
if ( macro - > second . expand ( & output2 , rawtok - > location , rawtokens2 . cfront ( ) , macros , expandedmacros ) ! = NULL )
2016-07-23 16:26:11 +02:00
break ;
rawtok = rawtok2 - > next ;
}
output - > takeTokens ( output2 ) ;
return rawtok ;
}
2016-07-20 12:21:00 +02:00
const TokenString & name ( ) const {
return nameToken - > str ;
}
const Location & defineLocation ( ) const {
return nameToken - > location ;
}
const std : : list < Location > & usage ( ) const {
return usageList ;
}
2016-07-23 16:26:11 +02:00
bool functionLike ( ) const {
return nameToken - > next & &
nameToken - > next - > op = = ' ( ' & &
sameline ( nameToken , nameToken - > next ) & &
nameToken - > next - > location . col = = nameToken - > location . col + nameToken - > str . size ( ) ;
}
2016-07-20 12:21:00 +02:00
struct Error {
Error ( const Location & loc , const std : : string & s ) : location ( loc ) , what ( s ) { }
Location location ;
std : : string what ;
} ;
struct wrongNumberOfParameters : public Error {
wrongNumberOfParameters ( const Location & loc , const std : : string & macroName ) : Error ( loc , " Syntax error. Wrong number of parameters for macro \' " + macroName + " \' . " ) { }
} ;
struct invalidHashHash : public Error {
invalidHashHash ( const Location & loc , const std : : string & macroName ) : Error ( loc , " Syntax error. Invalid ## usage when expanding \' " + macroName + " \' . " ) { }
} ;
private :
Token * newMacroToken ( const TokenString & str , const Location & loc , bool rawCode ) const {
Token * tok = new Token ( str , loc ) ;
if ( ! rawCode )
tok - > macro = nameToken - > str ;
return tok ;
}
void setMacroName ( TokenList * output , Token * token1 , const std : : set < std : : string > & expandedmacros1 ) const {
if ( ! expandedmacros1 . empty ( ) )
return ;
2016-07-29 08:46:38 +02:00
for ( Token * tok = token1 ? token1 - > next : output - > front ( ) ; tok ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
if ( ! tok - > macro . empty ( ) )
tok - > macro = nameToken - > str ;
}
}
void parseDefine ( const Token * nametoken ) {
nameToken = nametoken ;
variadic = false ;
if ( ! nameToken ) {
2016-07-21 15:05:29 +02:00
valueToken = endToken = NULL ;
2016-07-20 12:21:00 +02:00
args . clear ( ) ;
return ;
}
// function like macro..
if ( functionLike ( ) ) {
args . clear ( ) ;
const Token * argtok = nameToken - > next - > next ;
while ( argtok & & argtok - > op ! = ' ) ' ) {
if ( argtok - > op = = ' . ' & &
argtok - > next & & argtok - > next - > op = = ' . ' & &
argtok - > next - > next & & argtok - > next - > next - > op = = ' . ' & &
argtok - > next - > next - > next & & argtok - > next - > next - > next - > op = = ' ) ' ) {
variadic = true ;
if ( ! argtok - > previous - > name )
args . push_back ( " __VA_ARGS__ " ) ;
argtok = argtok - > next - > next - > next ; // goto ')'
break ;
}
if ( argtok - > op ! = ' , ' )
args . push_back ( argtok - > str ) ;
argtok = argtok - > next ;
}
2016-07-28 09:26:23 +02:00
valueToken = argtok ? argtok - > next : NULL ;
2016-07-20 12:21:00 +02:00
} else {
args . clear ( ) ;
valueToken = nameToken - > next ;
}
if ( ! sameline ( valueToken , nameToken ) )
2016-07-21 15:05:29 +02:00
valueToken = NULL ;
2016-07-20 12:21:00 +02:00
endToken = valueToken ;
while ( sameline ( endToken , nameToken ) )
endToken = endToken - > next ;
}
unsigned int getArgNum ( const TokenString & str ) const {
unsigned int par = 0 ;
while ( par < args . size ( ) ) {
if ( str = = args [ par ] )
return par ;
par + + ;
}
return ~ 0U ;
}
2016-07-31 12:10:30 +02:00
std : : vector < const Token * > getMacroParameters ( const Token * nameToken , bool calledInDefine ) const {
2016-07-23 16:26:11 +02:00
if ( ! nameToken - > next | | nameToken - > next - > op ! = ' ( ' | | ! functionLike ( ) )
2016-07-20 12:21:00 +02:00
return std : : vector < const Token * > ( ) ;
std : : vector < const Token * > parametertokens ;
parametertokens . push_back ( nameToken - > next ) ;
unsigned int par = 0U ;
2016-07-31 12:10:30 +02:00
for ( const Token * tok = nameToken - > next - > next ; calledInDefine ? sameline ( tok , nameToken ) : ( tok ! = NULL ) ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
if ( tok - > op = = ' ( ' )
+ + par ;
else if ( tok - > op = = ' ) ' ) {
if ( par = = 0U ) {
parametertokens . push_back ( tok ) ;
break ;
}
- - par ;
}
else if ( par = = 0U & & tok - > op = = ' , ' & & ( ! variadic | | parametertokens . size ( ) < args . size ( ) ) )
parametertokens . push_back ( tok ) ;
}
return parametertokens ;
}
2016-07-23 09:26:06 +02:00
const Token * appendTokens ( TokenList * tokens ,
const Token * lpar ,
const std : : map < TokenString , Macro > & macros ,
const std : : set < TokenString > & expandedmacros1 ,
const std : : set < TokenString > & expandedmacros ,
const std : : vector < const Token * > & parametertokens ) const {
if ( ! lpar | | lpar - > op ! = ' ( ' )
return NULL ;
unsigned int par = 0 ;
const Token * tok = lpar ;
while ( sameline ( lpar , tok ) ) {
if ( ! expandArg ( tokens , tok , tok - > location , macros , expandedmacros1 , expandedmacros , parametertokens ) )
tokens - > push_back ( new Token ( * tok ) ) ;
if ( tok - > op = = ' ( ' )
+ + par ;
else if ( tok - > op = = ' ) ' ) {
- - par ;
if ( par = = 0U )
break ;
}
tok = tok - > next ;
}
return sameline ( lpar , tok ) ? tok : NULL ;
}
2016-07-29 08:46:38 +02:00
const Token * expand ( TokenList * const output , const Location & loc , const Token * const nameToken , const std : : map < TokenString , Macro > & macros , std : : set < TokenString > expandedmacros ) const {
const std : : set < TokenString > expandedmacros1 ( expandedmacros ) ;
expandedmacros . insert ( nameToken - > str ) ;
usageList . push_back ( loc ) ;
if ( nameToken - > str = = " __FILE__ " ) {
output - > push_back ( new Token ( ' \" ' + loc . file ( ) + ' \" ' , loc ) ) ;
return nameToken - > next ;
}
if ( nameToken - > str = = " __LINE__ " ) {
output - > push_back ( new Token ( toString ( loc . line ) , loc ) ) ;
return nameToken - > next ;
}
if ( nameToken - > str = = " __COUNTER__ " ) {
2016-07-29 20:54:11 +02:00
output - > push_back ( new Token ( toString ( usageList . size ( ) - 1U ) , loc ) ) ;
2016-07-29 08:46:38 +02:00
return nameToken - > next ;
}
2016-07-31 12:10:30 +02:00
const bool calledInDefine = ( loc . fileIndex ! = nameToken - > location . fileIndex | |
loc . line < nameToken - > location . line ) ;
std : : vector < const Token * > parametertokens1 ( getMacroParameters ( nameToken , calledInDefine ) ) ;
2016-07-29 08:46:38 +02:00
if ( functionLike ( ) ) {
// No arguments => not macro expansion
if ( nameToken - > next & & nameToken - > next - > op ! = ' ( ' ) {
output - > push_back ( new Token ( nameToken - > str , loc ) ) ;
return nameToken - > next ;
}
// Parse macro-call
if ( variadic ) {
2016-07-29 20:54:11 +02:00
if ( parametertokens1 . size ( ) < args . size ( ) ) {
2016-07-29 08:46:38 +02:00
throw wrongNumberOfParameters ( nameToken - > location , name ( ) ) ;
}
} else {
2016-07-29 20:54:11 +02:00
if ( parametertokens1 . size ( ) ! = args . size ( ) + ( args . empty ( ) ? 2U : 1U ) )
2016-07-29 08:46:38 +02:00
throw wrongNumberOfParameters ( nameToken - > location , name ( ) ) ;
}
}
2016-07-29 20:54:11 +02: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 ) {
if ( tok - > str = = " __COUNTER__ " ) {
counter = true ;
break ;
}
}
const std : : map < TokenString , Macro > : : const_iterator m = macros . find ( " __COUNTER__ " ) ;
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 ) {
if ( tok - > str = = " __COUNTER__ " ) {
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 + + ;
}
}
}
}
}
Token * const output_end_1 = output - > back ( ) ;
2016-07-29 08:46:38 +02:00
// expand
for ( const Token * tok = valueToken ; tok ! = endToken ; ) {
if ( tok - > op ! = ' # ' ) {
// A##B => AB
if ( tok - > next & & tok - > next - > op = = ' # ' & & tok - > next - > next & & tok - > next - > next - > op = = ' # ' ) {
2016-07-29 20:54:11 +02:00
output - > push_back ( newMacroToken ( expandArgStr ( tok , parametertokens2 ) , loc , ! expandedmacros1 . empty ( ) ) ) ;
2016-07-29 08:46:38 +02:00
tok = tok - > next ;
} else {
2016-07-29 20:54:11 +02:00
tok = expandToken ( output , loc , tok , macros , expandedmacros1 , expandedmacros , parametertokens2 ) ;
2016-07-29 08:46:38 +02:00
}
continue ;
}
tok = tok - > next ;
if ( tok = = endToken ) {
output - > push_back ( new Token ( * tok - > previous ) ) ;
break ;
}
if ( tok - > op = = ' # ' ) {
// A##B => AB
Token * A = output - > back ( ) ;
if ( ! A )
throw invalidHashHash ( tok - > location , name ( ) ) ;
if ( ! sameline ( tok , tok - > next ) )
throw invalidHashHash ( tok - > location , name ( ) ) ;
2016-07-29 20:54:11 +02:00
std : : string strAB = A - > str + expandArgStr ( tok - > next , parametertokens2 ) ;
2016-07-29 08:46:38 +02:00
bool removeComma = false ;
if ( variadic & & strAB = = " , " & & tok - > previous - > previous - > str = = " , " & & args . size ( ) > = 1U & & tok - > next - > str = = args [ args . size ( ) - 1U ] )
removeComma = true ;
output - > deleteToken ( A ) ;
if ( ! removeComma ) {
TokenList tokens ( files ) ;
tokens . push_back ( new Token ( strAB , tok - > location ) ) ;
// TODO: For functionLike macros, push the (...)
2016-07-29 20:54:11 +02:00
expandToken ( output , loc , tokens . cfront ( ) , macros , expandedmacros1 , expandedmacros , parametertokens2 ) ;
2016-07-29 08:46:38 +02:00
}
2016-07-31 20:48:55 +02:00
tok = tok - > next - > next ;
2016-07-29 08:46:38 +02:00
} else {
// #123 => "123"
TokenList tokenListHash ( files ) ;
2016-07-29 20:54:11 +02:00
tok = expandToken ( & tokenListHash , loc , tok , macros , expandedmacros1 , expandedmacros , parametertokens2 ) ;
2016-07-29 08:46:38 +02:00
std : : string s ;
for ( const Token * hashtok = tokenListHash . cfront ( ) ; hashtok ; hashtok = hashtok - > next )
s + = hashtok - > str ;
output - > push_back ( newMacroToken ( ' \" ' + s + ' \" ' , loc , expandedmacros1 . empty ( ) ) ) ;
}
}
if ( ! functionLike ( ) )
setMacroName ( output , output_end_1 , expandedmacros1 ) ;
2016-07-29 20:54:11 +02:00
if ( ! parametertokens1 . empty ( ) )
parametertokens1 . swap ( parametertokens2 ) ;
return functionLike ( ) ? parametertokens2 . back ( ) - > next : nameToken - > next ;
2016-07-29 08:46:38 +02:00
}
2016-07-23 09:26:06 +02:00
2016-07-29 08:46:38 +02:00
const Token * expandToken ( TokenList * output , const Location & loc , const Token * tok , const std : : map < TokenString , Macro > & macros , const std : : set < TokenString > & expandedmacros1 , const std : : set < TokenString > & expandedmacros , const std : : vector < const Token * > & parametertokens ) const {
2016-07-20 12:21:00 +02:00
// Not name..
if ( ! tok - > name ) {
output - > push_back ( newMacroToken ( tok - > str , loc , false ) ) ;
return tok - > next ;
}
// Macro parameter..
2016-07-23 09:26:06 +02:00
{
TokenList temp ( files ) ;
if ( expandArg ( & temp , tok , loc , macros , expandedmacros1 , expandedmacros , parametertokens ) ) {
2016-07-29 08:46:38 +02:00
if ( ! ( temp . cback ( ) & & temp . cback ( ) - > name & & tok - > next & & tok - > next - > op = = ' ( ' ) ) {
2016-07-23 09:26:06 +02:00
output - > takeTokens ( temp ) ;
return tok - > next ;
}
2016-07-29 08:46:38 +02:00
const std : : map < TokenString , Macro > : : const_iterator it = macros . find ( temp . cback ( ) - > str ) ;
if ( it = = macros . end ( ) | | expandedmacros . find ( temp . cback ( ) - > str ) ! = expandedmacros . end ( ) ) {
2016-07-23 09:26:06 +02:00
output - > takeTokens ( temp ) ;
return tok - > next ;
}
const Macro & calledMacro = it - > second ;
if ( ! calledMacro . functionLike ( ) ) {
output - > takeTokens ( temp ) ;
return tok - > next ;
}
TokenList temp2 ( files ) ;
2016-07-29 08:46:38 +02:00
temp2 . push_back ( new Token ( temp . cback ( ) - > str , tok - > location ) ) ;
2016-07-23 09:26:06 +02:00
const Token * tok2 = appendTokens ( & temp2 , tok - > next , macros , expandedmacros1 , expandedmacros , parametertokens ) ;
if ( ! tok2 )
return tok - > next ;
output - > takeTokens ( temp ) ;
2016-07-29 08:46:38 +02:00
output - > deleteToken ( output - > back ( ) ) ;
calledMacro . expand ( output , loc , temp2 . cfront ( ) , macros , expandedmacros ) ;
2016-07-23 09:26:06 +02:00
return tok2 - > next ;
}
}
2016-07-20 12:21:00 +02:00
// Macro..
const std : : map < TokenString , Macro > : : const_iterator it = macros . find ( tok - > str ) ;
2016-07-23 16:26:11 +02:00
if ( it ! = macros . end ( ) & & expandedmacros . find ( tok - > str ) = = expandedmacros . end ( ) ) {
2016-07-20 12:21:00 +02:00
const Macro & calledMacro = it - > second ;
if ( ! calledMacro . functionLike ( ) )
return calledMacro . expand ( output , loc , tok , macros , expandedmacros ) ;
if ( ! sameline ( tok , tok - > next ) | | tok - > next - > op ! = ' ( ' ) {
2016-07-23 16:26:11 +02:00
output - > push_back ( newMacroToken ( tok - > str , loc , false ) ) ;
return tok - > next ;
2016-07-20 12:21:00 +02:00
}
TokenList tokens ( files ) ;
tokens . push_back ( new Token ( * tok ) ) ;
2016-07-23 09:26:06 +02:00
const Token * tok2 = appendTokens ( & tokens , tok - > next , macros , expandedmacros1 , expandedmacros , parametertokens ) ;
if ( ! tok2 ) {
2016-07-23 16:26:11 +02:00
output - > push_back ( newMacroToken ( tok - > str , loc , false ) ) ;
return tok - > next ;
2016-07-20 12:21:00 +02:00
}
2016-07-29 08:46:38 +02:00
calledMacro . expand ( output , loc , tokens . cfront ( ) , macros , expandedmacros ) ;
2016-07-20 12:21:00 +02:00
return tok2 - > next ;
}
output - > push_back ( newMacroToken ( tok - > str , loc , false ) ) ;
return tok - > next ;
}
bool expandArg ( TokenList * output , const Token * tok , const std : : vector < const Token * > & parametertokens ) const {
if ( ! tok - > name )
return false ;
const unsigned int argnr = getArgNum ( tok - > str ) ;
if ( argnr > = args . size ( ) )
return false ;
2016-07-24 08:51:35 +02:00
// empty variadic parameter
if ( variadic & & argnr + 1U > = parametertokens . size ( ) )
return true ;
2016-07-20 12:21:00 +02:00
for ( const Token * partok = parametertokens [ argnr ] - > next ; partok ! = parametertokens [ argnr + 1U ] ; partok = partok - > next )
output - > push_back ( new Token ( * partok ) ) ;
return true ;
}
2016-07-29 08:46:38 +02:00
bool expandArg ( TokenList * output , const Token * tok , const Location & loc , const std : : map < TokenString , Macro > & macros , const std : : set < TokenString > & expandedmacros1 , const std : : set < TokenString > & expandedmacros , const std : : vector < const Token * > & parametertokens ) const {
2016-07-20 12:21:00 +02:00
if ( ! tok - > name )
return false ;
const unsigned int argnr = getArgNum ( tok - > str ) ;
if ( argnr > = args . size ( ) )
return false ;
2016-07-24 08:51:35 +02:00
if ( variadic & & argnr + 1U > = parametertokens . size ( ) ) // empty variadic parameter
return true ;
2016-07-20 12:21:00 +02:00
for ( const Token * partok = parametertokens [ argnr ] - > next ; partok ! = parametertokens [ argnr + 1U ] ; ) {
const std : : map < TokenString , Macro > : : const_iterator it = macros . find ( partok - > str ) ;
if ( it ! = macros . end ( ) & & expandedmacros1 . find ( partok - > str ) = = expandedmacros1 . end ( ) )
partok = it - > second . expand ( output , loc , partok , macros , expandedmacros ) ;
else {
output - > push_back ( newMacroToken ( partok - > str , loc , expandedmacros1 . empty ( ) ) ) ;
partok = partok - > next ;
}
}
return true ;
}
std : : string expandArgStr ( const Token * tok , const std : : vector < const Token * > & parametertokens ) const {
TokenList tokens ( files ) ;
if ( expandArg ( & tokens , tok , parametertokens ) ) {
std : : string s ;
2016-07-29 08:46:38 +02:00
for ( const Token * tok2 = tokens . cfront ( ) ; tok2 ; tok2 = tok2 - > next )
2016-07-20 12:21:00 +02:00
s + = tok2 - > str ;
return s ;
}
return tok - > str ;
}
void setMacro ( Token * tok ) const {
while ( tok ) {
if ( ! tok - > macro . empty ( ) )
tok - > macro = nameToken - > str ;
tok = tok - > next ;
}
}
const Token * nameToken ;
std : : vector < TokenString > args ;
bool variadic ;
const Token * valueToken ;
const Token * endToken ;
std : : vector < std : : string > & files ;
TokenList tokenListDefine ;
mutable std : : list < Location > usageList ;
} ;
}
2016-07-24 09:59:57 +02:00
namespace simplecpp {
std : : string simplifyPath ( std : : string path ) {
2016-07-25 09:13:59 +02:00
std : : string : : size_type pos ;
2016-07-24 09:59:57 +02:00
// replace backslash separators
2016-07-25 09:13:59 +02:00
std : : replace ( path . begin ( ) , path . end ( ) , ' \\ ' , ' / ' ) ;
2016-07-24 09:59:57 +02:00
// "./" at the start
if ( path . size ( ) > 3 & & path . compare ( 0 , 2 , " ./ " ) = = 0 & & path [ 2 ] ! = ' / ' )
path . erase ( 0 , 2 ) ;
// remove "/./"
pos = 0 ;
while ( ( pos = path . find ( " /./ " , pos ) ) ! = std : : string : : npos ) {
path . erase ( pos , 2 ) ;
}
// remove "xyz/../"
2016-07-24 11:36:02 +02:00
pos = 1U ;
while ( ( pos = path . find ( " /../ " , pos ) ) ! = std : : string : : npos ) {
2016-07-24 09:59:57 +02:00
const std : : string : : size_type pos1 = path . rfind ( " / " , pos - 1U ) ;
2016-07-24 11:36:02 +02:00
if ( pos1 = = std : : string : : npos )
pos + + ;
else {
path . erase ( pos1 , pos - pos1 + 3 ) ;
pos = std : : min ( ( std : : string : : size_type ) 1 , pos1 ) ;
}
2016-07-24 09:59:57 +02:00
}
return path ;
}
}
2016-07-20 12:21:00 +02:00
namespace {
2016-07-20 20:07:16 +02:00
void simplifySizeof ( simplecpp : : TokenList & expr , const std : : map < std : : string , std : : size_t > & sizeOfType ) {
2016-07-29 08:46:38 +02:00
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
if ( tok - > str ! = " sizeof " )
continue ;
simplecpp : : Token * tok1 = tok - > next ;
simplecpp : : Token * tok2 = tok1 - > next ;
if ( tok1 - > op = = ' ( ' ) {
2016-07-20 15:04:03 +02:00
tok1 = tok1 - > next ;
2016-07-20 12:21:00 +02:00
while ( tok2 - > op ! = ' ) ' )
tok2 = tok2 - > next ;
}
2016-07-20 15:04:03 +02:00
std : : string type ;
2016-07-20 12:21:00 +02:00
for ( simplecpp : : Token * typeToken = tok1 ; typeToken ! = tok2 ; typeToken = typeToken - > next ) {
2016-07-20 15:04:03 +02:00
if ( ( typeToken - > str = = " unsigned " | | typeToken - > str = = " signed " ) & & typeToken - > next - > name )
continue ;
if ( typeToken - > str = = " * " & & type . find ( " * " ) ! = std : : string : : npos )
continue ;
if ( ! type . empty ( ) )
type + = ' ' ;
type + = typeToken - > str ;
2016-07-20 12:21:00 +02:00
}
2016-07-20 15:04:03 +02:00
const std : : map < std : : string , std : : size_t > : : const_iterator it = sizeOfType . find ( type ) ;
if ( it ! = sizeOfType . end ( ) )
2016-07-20 20:03:27 +02:00
tok - > setstr ( toString ( it - > second ) ) ;
2016-07-20 15:04:03 +02:00
else
continue ;
2016-07-20 12:21:00 +02:00
2016-07-20 15:04:03 +02:00
tok2 = tok2 - > next ;
2016-07-20 12:21:00 +02:00
while ( tok - > next ! = tok2 )
expr . deleteToken ( tok - > next ) ;
}
}
void simplifyName ( simplecpp : : TokenList & expr ) {
2016-07-23 09:26:06 +02:00
std : : set < std : : string > altop ;
altop . insert ( " and " ) ;
altop . insert ( " or " ) ;
altop . insert ( " bitand " ) ;
altop . insert ( " bitor " ) ;
2016-07-31 20:48:55 +02:00
altop . insert ( " not " ) ;
altop . insert ( " not_eq " ) ;
2016-07-23 09:26:06 +02:00
altop . insert ( " xor " ) ;
2016-07-29 08:46:38 +02:00
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; tok = tok - > next ) {
2016-07-23 09:26:06 +02:00
if ( tok - > name ) {
if ( altop . find ( tok - > str ) ! = altop . end ( ) ) {
2016-07-31 20:48:55 +02:00
bool alt ;
if ( tok - > str = = " not " ) {
alt = isAlternativeUnaryOp ( tok , tok - > str ) ;
} else {
alt = isAlternativeBinaryOp ( tok , tok - > str ) ;
}
2016-07-23 09:26:06 +02:00
if ( alt )
continue ;
}
2016-07-20 12:21:00 +02:00
tok - > setstr ( " 0 " ) ;
2016-07-23 09:26:06 +02:00
}
2016-07-20 12:21:00 +02:00
}
}
void simplifyNumbers ( simplecpp : : TokenList & expr ) {
2016-07-29 08:46:38 +02:00
for ( simplecpp : : Token * tok = expr . front ( ) ; tok ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
if ( tok - > str . size ( ) = = 1U )
continue ;
if ( tok - > str . compare ( 0 , 2 , " 0x " ) = = 0 )
2016-07-21 15:59:59 +02:00
tok - > setstr ( toString ( stringToULL ( tok - > str ) ) ) ;
2016-07-20 12:21:00 +02:00
else if ( tok - > str [ 0 ] = = ' \' ' )
2016-07-21 15:05:29 +02:00
tok - > setstr ( toString ( tok - > str [ 1 ] & 0xffU ) ) ;
2016-07-20 12:21:00 +02:00
}
}
2016-07-21 19:42:26 +02:00
long long evaluate ( simplecpp : : TokenList & expr , const std : : map < std : : string , std : : size_t > & sizeOfType ) {
2016-07-20 20:07:16 +02:00
simplifySizeof ( expr , sizeOfType ) ;
2016-07-20 12:21:00 +02:00
simplifyName ( expr ) ;
simplifyNumbers ( expr ) ;
expr . constFold ( ) ;
// TODO: handle invalid expressions
2016-07-29 08:46:38 +02:00
return expr . cfront ( ) & & expr . cfront ( ) = = expr . cback ( ) & & expr . cfront ( ) - > number ? stringToLL ( expr . cfront ( ) - > str ) : 0LL ;
2016-07-20 12:21:00 +02:00
}
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-07-21 21:04:54 +02:00
std : : string openHeader ( std : : ifstream & f , const simplecpp : : DUI & dui , const std : : string & sourcefile , const std : : string & header , bool systemheader ) {
if ( ! systemheader ) {
if ( sourcefile . find_first_of ( " \\ / " ) ! = std : : string : : npos ) {
const std : : string s = sourcefile . substr ( 0 , sourcefile . find_last_of ( " \\ / " ) + 1U ) + header ;
f . open ( s . c_str ( ) ) ;
if ( f . is_open ( ) )
2016-07-24 09:59:57 +02:00
return simplecpp : : simplifyPath ( s ) ;
2016-07-21 21:04:54 +02:00
} else {
f . open ( header . c_str ( ) ) ;
if ( f . is_open ( ) )
2016-07-24 09:59:57 +02:00
return simplecpp : : simplifyPath ( header ) ;
2016-07-21 21:04:54 +02:00
}
2016-07-20 12:21:00 +02:00
}
for ( std : : list < std : : string > : : const_iterator it = dui . includePaths . begin ( ) ; it ! = dui . includePaths . end ( ) ; + + it ) {
std : : string s = * it ;
if ( ! s . empty ( ) & & s [ s . size ( ) - 1U ] ! = ' / ' & & s [ s . size ( ) - 1U ] ! = ' \\ ' )
s + = ' / ' ;
s + = header ;
2016-07-21 15:05:29 +02:00
f . open ( s . c_str ( ) ) ;
2016-07-20 12:21:00 +02:00
if ( f . is_open ( ) )
2016-07-24 09:59:57 +02:00
return simplecpp : : simplifyPath ( s ) ;
2016-07-20 12:21:00 +02:00
}
return " " ;
}
2016-07-21 21:04:54 +02:00
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 ) {
if ( ! systemheader ) {
if ( sourcefile . find_first_of ( " \\ / " ) ! = std : : string : : npos ) {
2016-07-25 21:33:06 +02:00
const std : : string s ( simplecpp : : simplifyPath ( sourcefile . substr ( 0 , sourcefile . find_last_of ( " \\ / " ) + 1U ) + header ) ) ;
2016-07-21 21:04:54 +02:00
if ( filedata . find ( s ) ! = filedata . end ( ) )
2016-07-25 21:33:06 +02:00
return s ;
2016-07-21 21:04:54 +02:00
} else {
2016-07-25 21:33:06 +02:00
if ( filedata . find ( simplecpp : : simplifyPath ( header ) ) ! = filedata . end ( ) )
2016-07-24 09:59:57 +02:00
return simplecpp : : simplifyPath ( header ) ;
2016-07-21 21:04:54 +02:00
}
2016-07-20 12:21:00 +02:00
}
for ( std : : list < std : : string > : : const_iterator it = dui . includePaths . begin ( ) ; it ! = dui . includePaths . end ( ) ; + + it ) {
std : : string s = * it ;
if ( ! s . empty ( ) & & s [ s . size ( ) - 1U ] ! = ' / ' & & s [ s . size ( ) - 1U ] ! = ' \\ ' )
s + = ' / ' ;
s + = header ;
2016-07-25 21:33:06 +02:00
s = simplecpp : : simplifyPath ( s ) ;
2016-07-20 12:21:00 +02:00
if ( filedata . find ( s ) ! = filedata . end ( ) )
2016-07-25 21:33:06 +02:00
return s ;
2016-07-20 12:21:00 +02:00
}
return " " ;
}
2016-07-21 21:04:54 +02:00
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
}
}
2016-07-29 13:05:35 +02:00
std : : map < std : : string , simplecpp : : TokenList * > simplecpp : : load ( const simplecpp : : TokenList & rawtokens , std : : vector < std : : string > & fileNumbers , const simplecpp : : DUI & dui , simplecpp : : OutputList * outputList )
2016-07-20 12:21:00 +02:00
{
std : : map < std : : string , simplecpp : : TokenList * > ret ;
std : : list < const Token * > filelist ;
2016-07-29 08:46:38 +02:00
for ( const Token * rawtok = rawtokens . cfront ( ) ; rawtok | | ! filelist . empty ( ) ; rawtok = rawtok ? rawtok - > next : NULL ) {
2016-07-21 15:05:29 +02:00
if ( rawtok = = NULL ) {
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 ( ) ;
2016-07-20 12:21:00 +02:00
if ( ! rawtok | | rawtok - > str ! = INCLUDE )
continue ;
const std : : string & sourcefile = rawtok - > location . file ( ) ;
2016-07-21 18:58:11 +02:00
const Token * htok = rawtok - > nextSkipComments ( ) ;
if ( ! sameline ( rawtok , htok ) )
continue ;
2016-07-21 21:04:54 +02:00
bool systemheader = ( htok - > str [ 0 ] = = ' < ' ) ;
2016-07-21 18:58:11 +02:00
const std : : string header ( 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 ;
2016-07-21 21:04:54 +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 ;
2016-07-20 22:35:45 +02:00
ret [ header2 ] = 0 ;
2016-07-21 18:58:11 +02:00
TokenList * tokens = new TokenList ( f , fileNumbers , header2 , 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 ;
}
2016-07-29 13:05:35 +02:00
void simplecpp : : preprocess ( simplecpp : : TokenList & output , const simplecpp : : TokenList & rawtokens , std : : vector < std : : string > & files , const std : : map < std : : string , simplecpp : : TokenList * > & filedata , const simplecpp : : DUI & dui , simplecpp : : OutputList * outputList , std : : list < simplecpp : : MacroUsage > * macroUsage )
2016-07-20 12:21:00 +02:00
{
2016-07-20 20:07:16 +02:00
std : : map < std : : string , std : : size_t > sizeOfType ( rawtokens . sizeOfType ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " char " ) , sizeof ( char ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " short " ) , sizeof ( short ) ) ) ;
2016-07-28 09:26:23 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " short int " ) , sizeOfType [ " short " ] ) ) ;
2016-07-20 20:07:16 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " int " ) , sizeof ( int ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long " ) , sizeof ( long ) ) ) ;
2016-07-28 09:26:23 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long int " ) , sizeOfType [ " long " ] ) ) ;
2016-07-20 20:07:16 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long long " ) , sizeof ( long long ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " float " ) , sizeof ( float ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " double " ) , sizeof ( double ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long double " ) , sizeof ( long double ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " char * " ) , sizeof ( char * ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " short * " ) , sizeof ( short * ) ) ) ;
2016-07-28 09:26:23 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " short int * " ) , sizeOfType [ " short * " ] ) ) ;
2016-07-20 20:07:16 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " int * " ) , sizeof ( int * ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long * " ) , sizeof ( long * ) ) ) ;
2016-07-28 09:26:23 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long int * " ) , sizeOfType [ " long * " ] ) ) ;
2016-07-20 20:07:16 +02:00
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long long * " ) , sizeof ( long long * ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " float * " ) , sizeof ( float * ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " double * " ) , sizeof ( double * ) ) ) ;
sizeOfType . insert ( std : : pair < std : : string , std : : size_t > ( std : : string ( " long double * " ) , sizeof ( long double * ) ) ) ;
2016-07-20 12:21:00 +02:00
std : : map < TokenString , Macro > macros ;
for ( std : : list < std : : string > : : const_iterator it = dui . defines . begin ( ) ; it ! = dui . defines . end ( ) ; + + it ) {
const std : : string & macrostr = * it ;
const std : : string : : size_type eq = macrostr . find ( " = " ) ;
const std : : string : : size_type par = macrostr . find ( " ( " ) ;
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 ) ) ;
}
2016-07-25 09:13:59 +02:00
macros . insert ( std : : pair < TokenString , Macro > ( " __FILE__ " , Macro ( " __FILE__ " , " __FILE__ " , files ) ) ) ;
macros . insert ( std : : pair < TokenString , Macro > ( " __LINE__ " , Macro ( " __LINE__ " , " __LINE__ " , files ) ) ) ;
macros . insert ( std : : pair < TokenString , Macro > ( " __COUNTER__ " , Macro ( " __COUNTER__ " , " __COUNTER__ " , files ) ) ) ;
2016-07-20 12:21:00 +02:00
// TRUE => code in current #if block should be kept
// ELSE_IS_TRUE => code in current #if block should be dropped. the code in the #else should be kept.
// ALWAYS_FALSE => drop all code in #if and #else
enum IfState { TRUE , ELSE_IS_TRUE , ALWAYS_FALSE } ;
2016-07-21 15:05:29 +02:00
std : : stack < int > ifstates ;
2016-07-20 12:21:00 +02:00
ifstates . push ( TRUE ) ;
std : : list < TokenList * > includes ;
std : : stack < const Token * > includetokenstack ;
2016-07-21 12:47:00 +02:00
std : : set < std : : string > pragmaOnce ;
2016-07-29 08:46:38 +02:00
for ( const Token * rawtok = rawtokens . cfront ( ) ; rawtok | | ! includetokenstack . empty ( ) ; ) {
2016-07-21 15:05:29 +02:00
if ( rawtok = = NULL ) {
2016-07-20 12:21:00 +02:00
rawtok = includetokenstack . top ( ) ;
includetokenstack . pop ( ) ;
continue ;
}
if ( rawtok - > op = = ' # ' & & ! sameline ( rawtok - > previous , rawtok ) ) {
rawtok = rawtok - > next ;
2016-07-25 09:13:59 +02:00
if ( ! rawtok | | ! rawtok - > name ) {
if ( rawtok )
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
if ( ifstates . top ( ) = = TRUE & & ( rawtok - > str = = ERROR | | rawtok - > str = = WARNING ) ) {
if ( outputList ) {
simplecpp : : Output err ( rawtok - > location . files ) ;
err . type = rawtok - > str = = ERROR ? Output : : ERROR : Output : : WARNING ;
err . location = rawtok - > location ;
for ( const Token * tok = rawtok - > next ; tok & & sameline ( rawtok , tok ) ; tok = tok - > next ) {
2016-07-29 13:05:35 +02:00
if ( ! err . msg . empty ( ) & & isNameChar ( tok - > str [ 0 ] ) )
2016-07-20 12:21:00 +02:00
err . msg + = ' ' ;
err . msg + = tok - > str ;
}
err . msg = ' # ' + rawtok - > str + ' ' + err . msg ;
outputList - > push_back ( err ) ;
}
2016-07-21 19:42:26 +02:00
output . clear ( ) ;
return ;
2016-07-20 12:21:00 +02:00
}
if ( rawtok - > str = = DEFINE ) {
if ( ifstates . top ( ) ! = TRUE )
continue ;
try {
const Macro & macro = Macro ( rawtok - > previous , files ) ;
if ( dui . undefined . find ( macro . name ( ) ) = = dui . undefined . end ( ) ) {
std : : map < TokenString , Macro > : : iterator it = macros . find ( macro . name ( ) ) ;
if ( it = = macros . end ( ) )
macros . insert ( std : : pair < TokenString , Macro > ( macro . name ( ) , macro ) ) ;
else
it - > second = macro ;
}
} catch ( const std : : runtime_error & ) {
}
2016-07-21 12:47:00 +02:00
} else if ( ifstates . top ( ) = = TRUE & & rawtok - > str = = INCLUDE ) {
2016-07-21 21:04:54 +02:00
const bool systemheader = ( rawtok - > next - > str [ 0 ] = = ' < ' ) ;
2016-07-21 12:47:00 +02:00
const std : : string header ( rawtok - > next - > str . substr ( 1U , rawtok - > next - > str . size ( ) - 2U ) ) ;
2016-07-21 21:04:54 +02:00
const std : : string header2 = getFileName ( filedata , rawtok - > location . file ( ) , header , dui , systemheader ) ;
2016-07-31 12:10:30 +02:00
if ( header2 . empty ( ) ) {
2016-07-21 12:47:00 +02:00
simplecpp : : Output output ( files ) ;
2016-07-31 12:10:30 +02:00
output . type = Output : : MISSING_HEADER ;
2016-07-21 12:47:00 +02:00
output . location = rawtok - > location ;
output . msg = " Header not found: " + rawtok - > next - > str ;
if ( outputList )
outputList - > push_back ( output ) ;
2016-07-31 12:10:30 +02:00
} else if ( includetokenstack . size ( ) > = 400 ) {
simplecpp : : Output out ( files ) ;
out . type = Output : : INCLUDE_NESTED_TOO_DEEPLY ;
out . location = rawtok - > location ;
out . msg = " #include nested too deeply " ;
if ( outputList )
outputList - > push_back ( out ) ;
} else if ( pragmaOnce . find ( header2 ) = = pragmaOnce . end ( ) ) {
includetokenstack . push ( gotoNextLine ( rawtok ) ) ;
const TokenList * includetokens = filedata . find ( header2 ) - > second ;
rawtok = includetokens ? includetokens - > cfront ( ) : 0 ;
continue ;
2016-07-20 12:21:00 +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 ) ) {
simplecpp : : Output out ( files ) ;
out . type = Output : : SYNTAX_ERROR ;
out . location = rawtok - > location ;
out . msg = " Syntax error in # " + rawtok - > str ;
if ( outputList )
outputList - > push_back ( out ) ;
output . clear ( ) ;
return ;
}
2016-07-20 12:21:00 +02:00
bool conditionIsTrue ;
if ( ifstates . top ( ) = = ALWAYS_FALSE | | ( ifstates . top ( ) = = ELSE_IS_TRUE & & rawtok - > str ! = ELIF ) )
conditionIsTrue = false ;
else if ( rawtok - > str = = IFDEF )
conditionIsTrue = ( macros . find ( rawtok - > next - > str ) ! = macros . end ( ) ) ;
else if ( rawtok - > str = = IFNDEF )
conditionIsTrue = ( macros . find ( rawtok - > next - > str ) = = macros . end ( ) ) ;
else { /*if (rawtok->str == IF || rawtok->str == ELIF)*/
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 ;
}
if ( tok - > str = = DEFINED ) {
tok = tok - > next ;
const bool par = ( tok & & tok - > op = = ' ( ' ) ;
if ( par )
tok = tok - > next ;
if ( ! tok )
break ;
if ( macros . find ( tok - > str ) ! = macros . end ( ) )
expr . push_back ( new Token ( " 1 " , tok - > location ) ) ;
else
expr . push_back ( new Token ( " 0 " , tok - > location ) ) ;
if ( tok & & par )
tok = tok - > next ;
continue ;
}
const std : : map < std : : string , Macro > : : const_iterator it = macros . find ( tok - > str ) ;
if ( it ! = macros . end ( ) ) {
TokenList value ( files ) ;
try {
2016-07-23 16:26:11 +02:00
it - > second . expand ( & value , tok , macros , files ) ;
2016-07-20 12:21:00 +02:00
} catch ( Macro : : Error & err ) {
Output out ( rawtok - > location . files ) ;
2016-07-31 12:10:30 +02:00
out . type = Output : : SYNTAX_ERROR ;
2016-07-20 12:21:00 +02:00
out . location = err . location ;
out . msg = " failed to expand \' " + tok - > str + " \' , " + err . what ;
if ( outputList )
outputList - > push_back ( out ) ;
2016-07-21 19:42:26 +02:00
output . clear ( ) ;
return ;
2016-07-20 12:21:00 +02:00
}
2016-07-23 16:26:11 +02:00
expr . takeTokens ( value ) ;
2016-07-20 12:21:00 +02:00
} else {
expr . push_back ( new Token ( * tok ) ) ;
}
}
try {
2016-07-20 20:07:16 +02:00
conditionIsTrue = ( evaluate ( expr , sizeOfType ) ! = 0 ) ;
2016-07-20 12:21:00 +02:00
} catch ( const std : : exception & ) {
Output out ( rawtok - > location . files ) ;
out . type = Output : : ERROR ;
out . location = rawtok - > location ;
out . msg = " failed to evaluate " + std : : string ( rawtok - > str = = IF ? " #if " : " #elif " ) + " condition " ;
if ( outputList )
outputList - > push_back ( out ) ;
2016-07-21 19:42:26 +02:00
output . clear ( ) ;
return ;
2016-07-20 12:21:00 +02:00
}
}
if ( rawtok - > str ! = ELIF ) {
// push a new ifstate..
if ( ifstates . top ( ) ! = TRUE )
ifstates . push ( ALWAYS_FALSE ) ;
else
ifstates . push ( conditionIsTrue ? TRUE : ELSE_IS_TRUE ) ;
} else if ( ifstates . top ( ) = = TRUE ) {
ifstates . top ( ) = ALWAYS_FALSE ;
} else if ( ifstates . top ( ) = = ELSE_IS_TRUE & & conditionIsTrue ) {
ifstates . top ( ) = TRUE ;
}
} else if ( rawtok - > str = = ELSE ) {
ifstates . top ( ) = ( ifstates . top ( ) = = ELSE_IS_TRUE ) ? TRUE : ALWAYS_FALSE ;
} else if ( rawtok - > str = = ENDIF ) {
if ( ifstates . size ( ) > 1U )
ifstates . pop ( ) ;
} else if ( rawtok - > str = = UNDEF ) {
if ( ifstates . top ( ) = = TRUE ) {
const Token * tok = rawtok - > next ;
while ( sameline ( rawtok , tok ) & & tok - > comment )
tok = tok - > next ;
if ( sameline ( rawtok , tok ) )
macros . erase ( tok - > str ) ;
}
2016-07-21 12:47:00 +02:00
} else if ( ifstates . top ( ) = = TRUE & & rawtok - > str = = PRAGMA & & rawtok - > next & & rawtok - > next - > str = = ONCE & & sameline ( rawtok , rawtok - > next ) ) {
pragmaOnce . insert ( rawtok - > location . file ( ) ) ;
2016-07-20 12:21:00 +02:00
}
rawtok = gotoNextLine ( rawtok ) ;
continue ;
}
if ( ifstates . top ( ) ! = TRUE ) {
// 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-07-20 12:21:00 +02:00
if ( macros . find ( rawtok - > str ) ! = macros . end ( ) ) {
std : : map < TokenString , Macro > : : const_iterator macro = macros . find ( rawtok - > str ) ;
if ( macro ! = macros . end ( ) ) {
try {
2016-07-25 09:13:59 +02:00
rawtok = macro - > second . expand ( & tokens , rawtok , macros , files ) ;
2016-07-20 12:21:00 +02:00
} catch ( const simplecpp : : Macro : : Error & err ) {
Output out ( err . location . files ) ;
out . type = Output : : ERROR ;
out . location = err . location ;
out . msg = err . what ;
if ( outputList )
outputList - > push_back ( out ) ;
2016-07-21 19:42:26 +02:00
output . clear ( ) ;
return ;
2016-07-20 12:21:00 +02:00
}
}
}
2016-07-25 09:13:59 +02:00
else {
if ( ! rawtok - > comment )
tokens . push_back ( new Token ( * rawtok ) ) ;
rawtok = rawtok - > next ;
}
if ( hash | | hashhash ) {
std : : string s ;
2016-07-29 08:46:38 +02:00
for ( const Token * hashtok = tokens . cfront ( ) ; hashtok ; hashtok = hashtok - > next )
2016-07-25 09:13:59 +02:00
s + = hashtok - > str ;
if ( hash )
output . push_back ( new Token ( ' \" ' + s + ' \" ' , loc ) ) ;
2016-07-29 08:46:38 +02:00
else if ( output . back ( ) )
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 ) {
for ( std : : map < TokenString , simplecpp : : Macro > : : const_iterator macroIt = macros . begin ( ) ; macroIt ! = macros . end ( ) ; + + macroIt ) {
const Macro & macro = macroIt - > second ;
const std : : list < Location > & usage = macro . usage ( ) ;
for ( std : : list < Location > : : const_iterator usageIt = usage . begin ( ) ; usageIt ! = usage . end ( ) ; + + usageIt ) {
2016-07-29 13:05:35 +02:00
MacroUsage mu ( usageIt - > files ) ;
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
void simplecpp : : cleanup ( std : : map < std : : string , TokenList * > & filedata ) {
for ( std : : map < std : : string , TokenList * > : : iterator it = filedata . begin ( ) ; it ! = filedata . end ( ) ; + + it )
delete it - > second ;
filedata . clear ( ) ;
}