zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
MacroExpander.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "MacroExpander.h"
8 
9 #include <algorithm>
10 #include <sstream>
11 
12 #include "DiagnosticsBase.h"
13 #include "Token.h"
14 
15 namespace pp
16 {
17 
18 class TokenLexer : public Lexer
19 {
20  public:
21  typedef std::vector<Token> TokenVector;
22 
23  TokenLexer(TokenVector* tokens)
24  {
25  tokens->swap(mTokens);
26  mIter = mTokens.begin();
27  }
28 
29  virtual void lex(Token* token)
30  {
31  if (mIter == mTokens.end())
32  {
33  token->reset();
34  token->type = Token::LAST;
35  }
36  else
37  {
38  *token = *mIter++;
39  }
40  }
41 
42  private:
43  PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);
44 
45  TokenVector mTokens;
46  TokenVector::const_iterator mIter;
47 };
48 
50  MacroSet* macroSet,
51  Diagnostics* diagnostics) :
52  mLexer(lexer),
53  mMacroSet(macroSet),
54  mDiagnostics(diagnostics)
55 {
56 }
57 
59 {
60  for (std::size_t i = 0; i < mContextStack.size(); ++i)
61  {
62  delete mContextStack[i];
63  }
64 }
65 
67 {
68  while (true)
69  {
70  getToken(token);
71 
72  if (token->type != Token::IDENTIFIER)
73  break;
74 
75  if (token->expansionDisabled())
76  break;
77 
78  MacroSet::const_iterator iter = mMacroSet->find(token->text);
79  if (iter == mMacroSet->end())
80  break;
81 
82  const Macro& macro = iter->second;
83  if (macro.disabled)
84  {
85  // If a particular token is not expanded, it is never expanded.
86  token->setExpansionDisabled(true);
87  break;
88  }
89  if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
90  {
91  // If the token immediately after the macro name is not a '(',
92  // this macro should not be expanded.
93  break;
94  }
95 
96  pushMacro(macro, *token);
97  }
98 }
99 
100 void MacroExpander::getToken(Token* token)
101 {
102  if (mReserveToken.get())
103  {
104  *token = *mReserveToken;
105  mReserveToken.reset();
106  return;
107  }
108 
109  // First pop all empty macro contexts.
110  while (!mContextStack.empty() && mContextStack.back()->empty())
111  {
112  popMacro();
113  }
114 
115  if (!mContextStack.empty())
116  {
117  *token = mContextStack.back()->get();
118  }
119  else
120  {
121  mLexer->lex(token);
122  }
123 }
124 
125 void MacroExpander::ungetToken(const Token& token)
126 {
127  if (!mContextStack.empty())
128  {
129  MacroContext* context = mContextStack.back();
130  context->unget();
131  assert(context->replacements[context->index] == token);
132  }
133  else
134  {
135  assert(!mReserveToken.get());
136  mReserveToken.reset(new Token(token));
137  }
138 }
139 
140 bool MacroExpander::isNextTokenLeftParen()
141 {
142  Token token;
143  getToken(&token);
144 
145  bool lparen = token.type == '(';
146  ungetToken(token);
147 
148  return lparen;
149 }
150 
151 bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
152 {
153  assert(!macro.disabled);
154  assert(!identifier.expansionDisabled());
155  assert(identifier.type == Token::IDENTIFIER);
156  assert(identifier.text == macro.name);
157 
158  std::vector<Token> replacements;
159  if (!expandMacro(macro, identifier, &replacements))
160  return false;
161 
162  // Macro is disabled for expansion until it is popped off the stack.
163  macro.disabled = true;
164 
165  MacroContext* context = new MacroContext;
166  context->macro = &macro;
167  context->replacements.swap(replacements);
168  mContextStack.push_back(context);
169  return true;
170 }
171 
172 void MacroExpander::popMacro()
173 {
174  assert(!mContextStack.empty());
175 
176  MacroContext* context = mContextStack.back();
177  mContextStack.pop_back();
178 
179  assert(context->empty());
180  assert(context->macro->disabled);
181  context->macro->disabled = false;
182  delete context;
183 }
184 
185 bool MacroExpander::expandMacro(const Macro& macro,
186  const Token& identifier,
187  std::vector<Token>* replacements)
188 {
189  replacements->clear();
190  if (macro.type == Macro::kTypeObj)
191  {
192  replacements->assign(macro.replacements.begin(),
193  macro.replacements.end());
194 
195  if (macro.predefined)
196  {
197  static const std::string kLine = "__LINE__";
198  static const std::string kFile = "__FILE__";
199 
200  assert(replacements->size() == 1);
201  Token& repl = replacements->front();
202  if (macro.name == kLine)
203  {
204  std::ostringstream stream;
205  stream << identifier.location.line;
206  repl.text = stream.str();
207  }
208  else if (macro.name == kFile)
209  {
210  std::ostringstream stream;
211  stream << identifier.location.file;
212  repl.text = stream.str();
213  }
214  }
215  }
216  else
217  {
218  assert(macro.type == Macro::kTypeFunc);
219  std::vector<MacroArg> args;
220  args.reserve(macro.parameters.size());
221  if (!collectMacroArgs(macro, identifier, &args))
222  return false;
223 
224  replaceMacroParams(macro, args, replacements);
225  }
226 
227  for (std::size_t i = 0; i < replacements->size(); ++i)
228  {
229  Token& repl = replacements->at(i);
230  if (i == 0)
231  {
232  // The first token in the replacement list inherits the padding
233  // properties of the identifier token.
234  repl.setAtStartOfLine(identifier.atStartOfLine());
235  repl.setHasLeadingSpace(identifier.hasLeadingSpace());
236  }
237  repl.location = identifier.location;
238  }
239  return true;
240 }
241 
242 bool MacroExpander::collectMacroArgs(const Macro& macro,
243  const Token& identifier,
244  std::vector<MacroArg>* args)
245 {
246  Token token;
247  getToken(&token);
248  assert(token.type == '(');
249 
250  args->push_back(MacroArg());
251  for (int openParens = 1; openParens != 0; )
252  {
253  getToken(&token);
254 
255  if (token.type == Token::LAST)
256  {
258  identifier.location, identifier.text);
259  // Do not lose EOF token.
260  ungetToken(token);
261  return false;
262  }
263 
264  bool isArg = false; // True if token is part of the current argument.
265  switch (token.type)
266  {
267  case '(':
268  ++openParens;
269  isArg = true;
270  break;
271  case ')':
272  --openParens;
273  isArg = openParens != 0;
274  break;
275  case ',':
276  // The individual arguments are separated by comma tokens, but
277  // the comma tokens between matching inner parentheses do not
278  // seperate arguments.
279  if (openParens == 1) args->push_back(MacroArg());
280  isArg = openParens != 1;
281  break;
282  default:
283  isArg = true;
284  break;
285  }
286  if (isArg)
287  {
288  MacroArg& arg = args->back();
289  // Initial whitespace is not part of the argument.
290  if (arg.empty()) token.setHasLeadingSpace(false);
291  arg.push_back(token);
292  }
293  }
294 
295  const Macro::Parameters& params = macro.parameters;
296  // If there is only one empty argument, it is equivalent to no argument.
297  if (params.empty() && (args->size() == 1) && args->front().empty())
298  {
299  args->clear();
300  }
301  // Validate the number of arguments.
302  if (args->size() != params.size())
303  {
304  Diagnostics::ID id = args->size() < macro.parameters.size() ?
307  mDiagnostics->report(id, identifier.location, identifier.text);
308  return false;
309  }
310 
311  // Pre-expand each argument before substitution.
312  // This step expands each argument individually before they are
313  // inserted into the macro body.
314  for (std::size_t i = 0; i < args->size(); ++i)
315  {
316  MacroArg& arg = args->at(i);
317  TokenLexer lexer(&arg);
318  MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
319 
320  arg.clear();
321  expander.lex(&token);
322  while (token.type != Token::LAST)
323  {
324  arg.push_back(token);
325  expander.lex(&token);
326  }
327  }
328  return true;
329 }
330 
331 void MacroExpander::replaceMacroParams(const Macro& macro,
332  const std::vector<MacroArg>& args,
333  std::vector<Token>* replacements)
334 {
335  for (std::size_t i = 0; i < macro.replacements.size(); ++i)
336  {
337  const Token& repl = macro.replacements[i];
338  if (repl.type != Token::IDENTIFIER)
339  {
340  replacements->push_back(repl);
341  continue;
342  }
343 
344  // TODO(alokp): Optimize this.
345  // There is no need to search for macro params every time.
346  // The param index can be cached with the replacement token.
347  Macro::Parameters::const_iterator iter = std::find(
348  macro.parameters.begin(), macro.parameters.end(), repl.text);
349  if (iter == macro.parameters.end())
350  {
351  replacements->push_back(repl);
352  continue;
353  }
354 
355  std::size_t iArg = std::distance(macro.parameters.begin(), iter);
356  const MacroArg& arg = args[iArg];
357  if (arg.empty())
358  {
359  continue;
360  }
361  std::size_t iRepl = replacements->size();
362  replacements->insert(replacements->end(), arg.begin(), arg.end());
363  // The replacement token inherits padding properties from
364  // macro replacement token.
365  replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace());
366  }
367 }
368 
369 } // namespace pp
370 
Type type
Definition: Macro.h:35
virtual ~MacroExpander()
std::vector< std::string > Parameters
Definition: Macro.h:26
GLuint GLuint stream
Definition: glew.h:6573
bool expansionDisabled() const
Definition: Token.h:78
png_sPLT_entryp pp
Definition: pngrutil.c:1375
bool disabled
Definition: Macro.h:33
#define assert(x)
Definition: SDL_malloc.c:1234
GLenum GLvoid ** params
Definition: gl2ext.h:806
GLsizei GLsizei GLfloat distance
Definition: glew.h:12423
void setExpansionDisabled(bool disable)
Definition: Token.cpp:48
void report(ID id, const SourceLocation &loc, const std::string &text)
virtual void lex(Token *token)
std::map< std::string, Macro > MacroSet
Definition: Macro.h:41
MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics)
std::string text
Definition: Token.h:90
GLsizei const GLcharARB ** string
Definition: glew.h:5638
virtual void lex(Token *token)=0
int type
Definition: Token.h:87
TParseContext * context
int i
Definition: pngrutil.c:1377
#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: pp_utils.h:14
unsigned int size_t