@@ -58,6 +58,17 @@ static bool isOct(const std::string &s)
5858 return s.size ()>1 && (s[0 ]==' 0' ) && (s[1 ] >= ' 0' ) && (s[1 ] < ' 8' );
5959}
6060
61+ static bool isStringLiteral (const std::string &s)
62+ {
63+ return s.size () > 1 && (s[0 ]==' \" ' ) && (*s.rbegin ()==' \" ' );
64+ }
65+
66+ static bool isCharLiteral (const std::string &s)
67+ {
68+ // char literal patterns can include 'a', '\t', '\000', '\xff', 'abcd', and maybe ''
69+ // This only checks for the surrounding '' but doesn't parse the content.
70+ return s.size () > 1 && (s[0 ]==' \' ' ) && (*s.rbegin ()==' \' ' );
71+ }
6172
6273static const simplecpp::TokenString DEFINE (" define" );
6374static const simplecpp::TokenString UNDEF (" undef" );
@@ -1922,7 +1933,8 @@ namespace simplecpp {
19221933 throw invalidHashHash (tok->location , name ());
19231934
19241935 bool canBeConcatenatedWithEqual = A->isOneOf (" +-*/%&|^" ) || A->str () == " <<" || A->str () == " >>" ;
1925- if (!A->name && !A->number && A->op != ' ,' && !A->str ().empty () && !canBeConcatenatedWithEqual)
1936+ bool canBeConcatenatedStringOrChar = isStringLiteral (A->str ()) || isCharLiteral (A->str ());
1937+ if (!A->name && !A->number && A->op != ' ,' && !A->str ().empty () && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar)
19261938 throw invalidHashHash (tok->location , name ());
19271939
19281940 Token *B = tok->next ->next ;
@@ -1933,55 +1945,73 @@ namespace simplecpp {
19331945 (!canBeConcatenatedWithEqual && B->op == ' =' ))
19341946 throw invalidHashHash (tok->location , name ());
19351947
1936- std::string strAB;
1937-
1938- const bool varargs = variadic && args. size () >= 1U && B-> str () == args[args. size ()- 1U ] ;
1948+ // Superficial check; more in-depth would in theory be possible _after_ expandArg
1949+ if (canBeConcatenatedStringOrChar && (B-> number || !B-> name ))
1950+ throw invalidHashHash (tok-> location , name ()) ;
19391951
19401952 TokenList tokensB (files);
1941- if (expandArg (&tokensB, B, parametertokens)) {
1942- if (tokensB.empty ())
1943- strAB = A->str ();
1944- else if (varargs && A->op == ' ,' ) {
1945- strAB = " ," ;
1953+ const Token *nextTok = B->next ;
1954+
1955+ if (canBeConcatenatedStringOrChar) {
1956+ // It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here.
1957+ // TODO The question is whether the ## or varargs may still apply, and how to provoke?
1958+ if (expandArg (&tokensB, B, parametertokens)) {
1959+ for (Token *b = tokensB.front (); b; b = b->next )
1960+ b->location = loc;
19461961 } else {
1947- strAB = A-> str () + tokensB.cfront ()-> str ( );
1948- tokensB.deleteToken (tokensB. front ()) ;
1962+ tokensB.push_back ( new Token (*B) );
1963+ tokensB.back ()-> location = loc ;
19491964 }
1950- } else {
1951- strAB = A->str () + B->str ();
1952- }
1953-
1954- const Token *nextTok = B->next ;
1955- if (varargs && tokensB.empty () && tok->previous ->str () == " ," )
1956- output->deleteToken (A);
1957- else if (strAB != " ," && macros.find (strAB) == macros.end ()) {
1958- A->setstr (strAB);
1959- for (Token *b = tokensB.front (); b; b = b->next )
1960- b->location = loc;
19611965 output->takeTokens (tokensB);
1962- } else if (nextTok->op == ' #' && nextTok->next ->op == ' #' ) {
1963- TokenList output2 (files);
1964- output2.push_back (new Token (strAB, tok->location ));
1965- nextTok = expandHashHash (&output2, loc, nextTok, macros, expandedmacros, parametertokens);
1966- output->deleteToken (A);
1967- output->takeTokens (output2);
19681966 } else {
1969- output->deleteToken (A);
1970- TokenList tokens (files);
1971- tokens.push_back (new Token (strAB, tok->location ));
1972- // for function like macros, push the (...)
1973- if (tokensB.empty () && sameline (B,B->next ) && B->next ->op ==' (' ) {
1974- const MacroMap::const_iterator it = macros.find (strAB);
1975- if (it != macros.end () && expandedmacros.find (strAB) == expandedmacros.end () && it->second .functionLike ()) {
1976- const Token *tok2 = appendTokens (&tokens, loc, B->next , macros, expandedmacros, parametertokens);
1977- if (tok2)
1978- nextTok = tok2->next ;
1967+ std::string strAB;
1968+
1969+ const bool varargs = variadic && args.size () >= 1U && B->str () == args[args.size ()-1U ];
1970+
1971+ if (expandArg (&tokensB, B, parametertokens)) {
1972+ if (tokensB.empty ())
1973+ strAB = A->str ();
1974+ else if (varargs && A->op == ' ,' ) {
1975+ strAB = " ," ;
1976+ } else {
1977+ strAB = A->str () + tokensB.cfront ()->str ();
1978+ tokensB.deleteToken (tokensB.front ());
1979+ }
1980+ } else {
1981+ strAB = A->str () + B->str ();
1982+ }
1983+
1984+ if (varargs && tokensB.empty () && tok->previous ->str () == " ," )
1985+ output->deleteToken (A);
1986+ else if (strAB != " ," && macros.find (strAB) == macros.end ()) {
1987+ A->setstr (strAB);
1988+ for (Token *b = tokensB.front (); b; b = b->next )
1989+ b->location = loc;
1990+ output->takeTokens (tokensB);
1991+ } else if (nextTok->op == ' #' && nextTok->next ->op == ' #' ) {
1992+ TokenList output2 (files);
1993+ output2.push_back (new Token (strAB, tok->location ));
1994+ nextTok = expandHashHash (&output2, loc, nextTok, macros, expandedmacros, parametertokens);
1995+ output->deleteToken (A);
1996+ output->takeTokens (output2);
1997+ } else {
1998+ output->deleteToken (A);
1999+ TokenList tokens (files);
2000+ tokens.push_back (new Token (strAB, tok->location ));
2001+ // for function like macros, push the (...)
2002+ if (tokensB.empty () && sameline (B,B->next ) && B->next ->op ==' (' ) {
2003+ const MacroMap::const_iterator it = macros.find (strAB);
2004+ if (it != macros.end () && expandedmacros.find (strAB) == expandedmacros.end () && it->second .functionLike ()) {
2005+ const Token *tok2 = appendTokens (&tokens, loc, B->next , macros, expandedmacros, parametertokens);
2006+ if (tok2)
2007+ nextTok = tok2->next ;
2008+ }
19792009 }
2010+ expandToken (output, loc, tokens.cfront (), macros, expandedmacros, parametertokens);
2011+ for (Token *b = tokensB.front (); b; b = b->next )
2012+ b->location = loc;
2013+ output->takeTokens (tokensB);
19802014 }
1981- expandToken (output, loc, tokens.cfront (), macros, expandedmacros, parametertokens);
1982- for (Token *b = tokensB.front (); b; b = b->next )
1983- b->location = loc;
1984- output->takeTokens (tokensB);
19852015 }
19862016
19872017 return nextTok;
0 commit comments