104d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org// 204d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. 304d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org// Use of this source code is governed by a BSD-style license that can be 404d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org// found in the LICENSE file. 504d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org// 604d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org 704d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org#include "MacroExpander.h" 804d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org 97fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org#include <algorithm> 10f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org#include <sstream> 117fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 12b3077d086b365b1d54c3d755df19c6f8f349a562daniel@transgaming.com#include "DiagnosticsBase.h" 137fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org#include "Token.h" 147fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1504d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.orgnamespace pp 1604d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org{ 1704d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org 187fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.orgclass TokenLexer : public Lexer 197fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 207fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org public: 217fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org typedef std::vector<Token> TokenVector; 227fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 23d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo TokenLexer(TokenVector *tokens) 247fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 257fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org tokens->swap(mTokens); 267fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org mIter = mTokens.begin(); 277fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 287fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 29d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo virtual void lex(Token *token) 307fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 317fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (mIter == mTokens.end()) 327fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 337fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org token->reset(); 347fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org token->type = Token::LAST; 357fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 367fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org else 377fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 387fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org *token = *mIter++; 397fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 407fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 417fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 427fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org private: 437fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer); 447fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 457fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org TokenVector mTokens; 467fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org TokenVector::const_iterator mIter; 477fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org}; 487fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 49d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao MoMacroExpander::MacroExpander(Lexer *lexer, 50d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo MacroSet *macroSet, 51d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo Diagnostics *diagnostics) 52d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo : mLexer(lexer), 53d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo mMacroSet(macroSet), 54d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo mDiagnostics(diagnostics) 5504d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org{ 5604d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org} 5704d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org 587fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.orgMacroExpander::~MacroExpander() 597fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 60a16a55f7286ac5b4bbfc0d767e6e55e5714fa062daniel@transgaming.com for (std::size_t i = 0; i < mContextStack.size(); ++i) 616c0c2d87aaa51ec9242284f6d1de9e79a9db771calokp@chromium.org { 626c0c2d87aaa51ec9242284f6d1de9e79a9db771calokp@chromium.org delete mContextStack[i]; 636c0c2d87aaa51ec9242284f6d1de9e79a9db771calokp@chromium.org } 647fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 657fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 66d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Movoid MacroExpander::lex(Token *token) 6704d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org{ 687fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org while (true) 697fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 707fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org getToken(token); 717fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 727fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (token->type != Token::IDENTIFIER) 737fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 747fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 757fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (token->expansionDisabled()) 767fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 777fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 785b6a68e04a7d27dab71524fa481f42818f84a240alokp@chromium.org MacroSet::const_iterator iter = mMacroSet->find(token->text); 797fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (iter == mMacroSet->end()) 807fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 817fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 827fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org const Macro& macro = iter->second; 837fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (macro.disabled) 847fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 857fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // If a particular token is not expanded, it is never expanded. 867fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org token->setExpansionDisabled(true); 877fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 887fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 897fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen()) 907fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 917fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // If the token immediately after the macro name is not a '(', 927fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // this macro should not be expanded. 937fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 947fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 957fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 967fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org pushMacro(macro, *token); 977fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 987fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 997fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 100d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Movoid MacroExpander::getToken(Token *token) 1017fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 1027fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (mReserveToken.get()) 1037fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 1047fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org *token = *mReserveToken; 1057fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org mReserveToken.reset(); 1067fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return; 1077fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 1087fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1097fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // First pop all empty macro contexts. 1107fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org while (!mContextStack.empty() && mContextStack.back()->empty()) 1117fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 1127fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org popMacro(); 1137fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 1147fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1157fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (!mContextStack.empty()) 1167fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 1177fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org *token = mContextStack.back()->get(); 1187fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 1197fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org else 1207fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 1217fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org mLexer->lex(token); 1227fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 1237fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 1247fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 125d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Movoid MacroExpander::ungetToken(const Token &token) 1267fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 1277fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (!mContextStack.empty()) 1287fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 129d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo MacroContext *context = mContextStack.back(); 1307fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org context->unget(); 1317fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(context->replacements[context->index] == token); 1327fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 1337fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org else 1347fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 1357fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(!mReserveToken.get()); 1367fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org mReserveToken.reset(new Token(token)); 1377fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 1387fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 1397fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1407fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.orgbool MacroExpander::isNextTokenLeftParen() 1417fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 1427fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org Token token; 1437fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org getToken(&token); 1447fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1457fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org bool lparen = token.type == '('; 1467fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org ungetToken(token); 1477fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1487fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return lparen; 1497fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 1507fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 151d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mobool MacroExpander::pushMacro(const Macro ¯o, const Token &identifier) 1527fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 1537fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(!macro.disabled); 1547fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(!identifier.expansionDisabled()); 1557fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(identifier.type == Token::IDENTIFIER); 1565b6a68e04a7d27dab71524fa481f42818f84a240alokp@chromium.org assert(identifier.text == macro.name); 1577fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1587fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org std::vector<Token> replacements; 1597fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (!expandMacro(macro, identifier, &replacements)) 1607fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return false; 1617fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1627fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // Macro is disabled for expansion until it is popped off the stack. 1637fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org macro.disabled = true; 1647fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 165d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo MacroContext *context = new MacroContext; 1667fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org context->macro = ¯o; 1677fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org context->replacements.swap(replacements); 1687fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org mContextStack.push_back(context); 1697fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return true; 1707fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 1717fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1727fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.orgvoid MacroExpander::popMacro() 1737fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 1747fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(!mContextStack.empty()); 1757fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 176d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo MacroContext *context = mContextStack.back(); 1777fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org mContextStack.pop_back(); 1787fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 1797fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(context->empty()); 1807fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(context->macro->disabled); 1817fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org context->macro->disabled = false; 1827fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org delete context; 1837fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 1847fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 185d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mobool MacroExpander::expandMacro(const Macro ¯o, 186d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo const Token &identifier, 187d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo std::vector<Token> *replacements) 1887fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 189f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org replacements->clear(); 1907fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (macro.type == Macro::kTypeObj) 1917fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 1927fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org replacements->assign(macro.replacements.begin(), 1937fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org macro.replacements.end()); 194f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org 195f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org if (macro.predefined) 196f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org { 197f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org static const std::string kLine = "__LINE__"; 198f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org static const std::string kFile = "__FILE__"; 199f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org 200f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org assert(replacements->size() == 1); 201f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org Token& repl = replacements->front(); 202f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org if (macro.name == kLine) 203f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org { 204f115592d96dc61ffca5cc23cd13a2ccd1743017falokp@chromium.org std::ostringstream stream; 205f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org stream << identifier.location.line; 2065b6a68e04a7d27dab71524fa481f42818f84a240alokp@chromium.org repl.text = stream.str(); 207f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org } 208f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org else if (macro.name == kFile) 209f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org { 210f115592d96dc61ffca5cc23cd13a2ccd1743017falokp@chromium.org std::ostringstream stream; 211f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org stream << identifier.location.file; 2125b6a68e04a7d27dab71524fa481f42818f84a240alokp@chromium.org repl.text = stream.str(); 213f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org } 214f3cdb460d1dde723815eecd006274a3da5d81099alokp@chromium.org } 2157fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2167fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org else 2177fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 2187fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(macro.type == Macro::kTypeFunc); 2197fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org std::vector<MacroArg> args; 2207fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org args.reserve(macro.parameters.size()); 2217fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (!collectMacroArgs(macro, identifier, &args)) 2227fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return false; 2237fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 2247fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org replaceMacroParams(macro, args, replacements); 2257fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2267fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 227a16a55f7286ac5b4bbfc0d767e6e55e5714fa062daniel@transgaming.com for (std::size_t i = 0; i < replacements->size(); ++i) 2287fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 2297fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org Token& repl = replacements->at(i); 2307fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (i == 0) 2317fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 2327fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // The first token in the replacement list inherits the padding 2337fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // properties of the identifier token. 2347fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org repl.setAtStartOfLine(identifier.atStartOfLine()); 2357fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org repl.setHasLeadingSpace(identifier.hasLeadingSpace()); 2367fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2377fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org repl.location = identifier.location; 2387fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2397fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return true; 2407fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 2417fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 242d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mobool MacroExpander::collectMacroArgs(const Macro ¯o, 243d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo const Token &identifier, 244d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo std::vector<MacroArg> *args) 2457fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 2467fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org Token token; 2477fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org getToken(&token); 2487fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org assert(token.type == '('); 2497fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 2507fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org args->push_back(MacroArg()); 2517fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org for (int openParens = 1; openParens != 0; ) 2527fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 2537fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org getToken(&token); 2547fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 2557fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (token.type == Token::LAST) 2567fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 2577f2d7945ee702241829727751bd4c7424662b225Shannon Woods mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, 2585b6a68e04a7d27dab71524fa481f42818f84a240alokp@chromium.org identifier.location, identifier.text); 2597fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // Do not lose EOF token. 2607fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org ungetToken(token); 2617fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return false; 2627fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2637fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 2647fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org bool isArg = false; // True if token is part of the current argument. 2657fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org switch (token.type) 2667fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 2677fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org case '(': 2687fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org ++openParens; 2697fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org isArg = true; 2707fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 2717fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org case ')': 2727fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org --openParens; 2737fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org isArg = openParens != 0; 2747fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 2757fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org case ',': 2767fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // The individual arguments are separated by comma tokens, but 2777fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // the comma tokens between matching inner parentheses do not 2787fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // seperate arguments. 279d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo if (openParens == 1) 280d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo args->push_back(MacroArg()); 2817fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org isArg = openParens != 1; 2827fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 2837fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org default: 2847fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org isArg = true; 2857fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org break; 2867fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2877fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (isArg) 2887fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 289d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo MacroArg &arg = args->back(); 2907fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // Initial whitespace is not part of the argument. 291d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo if (arg.empty()) 292d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo token.setHasLeadingSpace(false); 2937fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org arg.push_back(token); 2947fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2957fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 2967fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 297d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo const Macro::Parameters ¶ms = macro.parameters; 2987fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // If there is only one empty argument, it is equivalent to no argument. 2997fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (params.empty() && (args->size() == 1) && args->front().empty()) 3007fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 3017fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org args->clear(); 3027fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 3037fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // Validate the number of arguments. 3047fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (args->size() != params.size()) 3057fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 3067fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org Diagnostics::ID id = args->size() < macro.parameters.size() ? 3077f2d7945ee702241829727751bd4c7424662b225Shannon Woods Diagnostics::PP_MACRO_TOO_FEW_ARGS : 3087f2d7945ee702241829727751bd4c7424662b225Shannon Woods Diagnostics::PP_MACRO_TOO_MANY_ARGS; 3095b6a68e04a7d27dab71524fa481f42818f84a240alokp@chromium.org mDiagnostics->report(id, identifier.location, identifier.text); 3107fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return false; 3117fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 3127fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 3137fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // Pre-expand each argument before substitution. 3147fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // This step expands each argument individually before they are 3157fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // inserted into the macro body. 316a16a55f7286ac5b4bbfc0d767e6e55e5714fa062daniel@transgaming.com for (std::size_t i = 0; i < args->size(); ++i) 3177fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 318d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo MacroArg &arg = args->at(i); 3197fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org TokenLexer lexer(&arg); 3207fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org MacroExpander expander(&lexer, mMacroSet, mDiagnostics); 3217fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 3227fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org arg.clear(); 3237fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org expander.lex(&token); 3247fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org while (token.type != Token::LAST) 3257fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 3267fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org arg.push_back(token); 3277fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org expander.lex(&token); 3287fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 3297fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 3307fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org return true; 3317fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org} 3327fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 333d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Movoid MacroExpander::replaceMacroParams(const Macro ¯o, 334d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo const std::vector<MacroArg> &args, 335d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo std::vector<Token> *replacements) 3367fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org{ 337a16a55f7286ac5b4bbfc0d767e6e55e5714fa062daniel@transgaming.com for (std::size_t i = 0; i < macro.replacements.size(); ++i) 3387fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 339d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo const Token &repl = macro.replacements[i]; 3407fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (repl.type != Token::IDENTIFIER) 3417fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 3427fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org replacements->push_back(repl); 3437fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org continue; 3447fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 3457fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 3467fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // TODO(alokp): Optimize this. 3477fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // There is no need to search for macro params every time. 3487fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // The param index can be cached with the replacement token. 3497fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org Macro::Parameters::const_iterator iter = std::find( 3505b6a68e04a7d27dab71524fa481f42818f84a240alokp@chromium.org macro.parameters.begin(), macro.parameters.end(), repl.text); 3517fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (iter == macro.parameters.end()) 3527fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 3537fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org replacements->push_back(repl); 3547fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org continue; 3557fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 3567fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org 357a16a55f7286ac5b4bbfc0d767e6e55e5714fa062daniel@transgaming.com std::size_t iArg = std::distance(macro.parameters.begin(), iter); 358d526f9895c0aa867adb74a78e53832a9240c6ad6Zhenyao Mo const MacroArg &arg = args[iArg]; 3597fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org if (arg.empty()) 3607fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org { 3617fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org continue; 3627fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 363a16a55f7286ac5b4bbfc0d767e6e55e5714fa062daniel@transgaming.com std::size_t iRepl = replacements->size(); 3647fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org replacements->insert(replacements->end(), arg.begin(), arg.end()); 3657fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // The replacement token inherits padding properties from 3667fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org // macro replacement token. 3677fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace()); 3687fc38dddd2f5b6349348230475ca359666af583aalokp@chromium.org } 36904d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org} 37004d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org 37104d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org} // namespace pp 37204d7d22bb835408a82600244e09b9dcacbc0fa11alokp@chromium.org 373