blob: 9834b9bc3451e44451f350ff6de2894383c243ae [file] [log] [blame]
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001//
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +00002// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved.
alokp@chromium.org04d7d222012-05-16 19:24:07 +00003// 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 "DirectiveParser.h"
8
9#include <cassert>
alokp@chromium.org51b96852012-05-30 20:25:05 +000010#include <cstdlib>
alokp@chromium.org36124de82012-05-24 02:17:43 +000011#include <sstream>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000012
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000013#include "DiagnosticsBase.h"
14#include "DirectiveHandlerBase.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000015#include "ExpressionParser.h"
16#include "MacroExpander.h"
17#include "Token.h"
18#include "Tokenizer.h"
19
20namespace {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000021enum DirectiveType
22{
23 DIRECTIVE_NONE,
24 DIRECTIVE_DEFINE,
25 DIRECTIVE_UNDEF,
26 DIRECTIVE_IF,
27 DIRECTIVE_IFDEF,
28 DIRECTIVE_IFNDEF,
29 DIRECTIVE_ELSE,
30 DIRECTIVE_ELIF,
31 DIRECTIVE_ENDIF,
32 DIRECTIVE_ERROR,
33 DIRECTIVE_PRAGMA,
34 DIRECTIVE_EXTENSION,
35 DIRECTIVE_VERSION,
36 DIRECTIVE_LINE
37};
alokp@chromium.org04d7d222012-05-16 19:24:07 +000038} // namespace
39
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000040static DirectiveType getDirective(const pp::Token* token)
41{
42 static const std::string kDirectiveDefine("define");
43 static const std::string kDirectiveUndef("undef");
44 static const std::string kDirectiveIf("if");
45 static const std::string kDirectiveIfdef("ifdef");
46 static const std::string kDirectiveIfndef("ifndef");
47 static const std::string kDirectiveElse("else");
48 static const std::string kDirectiveElif("elif");
49 static const std::string kDirectiveEndif("endif");
50 static const std::string kDirectiveError("error");
51 static const std::string kDirectivePragma("pragma");
52 static const std::string kDirectiveExtension("extension");
53 static const std::string kDirectiveVersion("version");
54 static const std::string kDirectiveLine("line");
55
56 if (token->type != pp::Token::IDENTIFIER)
57 return DIRECTIVE_NONE;
58
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000059 if (token->text == kDirectiveDefine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000060 return DIRECTIVE_DEFINE;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000061 else if (token->text == kDirectiveUndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000062 return DIRECTIVE_UNDEF;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000063 else if (token->text == kDirectiveIf)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000064 return DIRECTIVE_IF;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000065 else if (token->text == kDirectiveIfdef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000066 return DIRECTIVE_IFDEF;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000067 else if (token->text == kDirectiveIfndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000068 return DIRECTIVE_IFNDEF;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000069 else if (token->text == kDirectiveElse)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000070 return DIRECTIVE_ELSE;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000071 else if (token->text == kDirectiveElif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000072 return DIRECTIVE_ELIF;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000073 else if (token->text == kDirectiveEndif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000074 return DIRECTIVE_ENDIF;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000075 else if (token->text == kDirectiveError)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000076 return DIRECTIVE_ERROR;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000077 else if (token->text == kDirectivePragma)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000078 return DIRECTIVE_PRAGMA;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000079 else if (token->text == kDirectiveExtension)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000080 return DIRECTIVE_EXTENSION;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000081 else if (token->text == kDirectiveVersion)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000082 return DIRECTIVE_VERSION;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000083 else if (token->text == kDirectiveLine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000084 return DIRECTIVE_LINE;
85
86 return DIRECTIVE_NONE;
87}
88
89static bool isConditionalDirective(DirectiveType directive)
90{
91 switch (directive)
92 {
93 case DIRECTIVE_IF:
94 case DIRECTIVE_IFDEF:
95 case DIRECTIVE_IFNDEF:
96 case DIRECTIVE_ELSE:
97 case DIRECTIVE_ELIF:
98 case DIRECTIVE_ENDIF:
99 return true;
100 default:
101 return false;
102 }
103}
104
105// Returns true if the token represents End Of Directive.
106static bool isEOD(const pp::Token* token)
107{
108 return (token->type == '\n') || (token->type == pp::Token::LAST);
109}
110
111static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
112{
113 while(!isEOD(token))
114 {
115 lexer->lex(token);
116 }
117}
118
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000119static bool isMacroNameReserved(const std::string& name)
120{
121 // Names prefixed with "GL_" are reserved.
122 if (name.substr(0, 3) == "GL_")
123 return true;
124
125 // Names containing two consecutive underscores are reserved.
126 if (name.find("__") != std::string::npos)
127 return true;
128
129 return false;
130}
131
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000132static bool isMacroPredefined(const std::string& name,
133 const pp::MacroSet& macroSet)
134{
135 pp::MacroSet::const_iterator iter = macroSet.find(name);
136 return iter != macroSet.end() ? iter->second.predefined : false;
137}
138
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000139namespace pp
140{
141
142class DefinedParser : public Lexer
143{
144 public:
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000145 DefinedParser(Lexer* lexer,
146 const MacroSet* macroSet,
147 Diagnostics* diagnostics) :
148 mLexer(lexer),
149 mMacroSet(macroSet),
150 mDiagnostics(diagnostics)
151 {
152 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000153
154 protected:
155 virtual void lex(Token* token)
156 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000157 static const std::string kDefined("defined");
158
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000159 mLexer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000160 if (token->type != Token::IDENTIFIER)
161 return;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000162 if (token->text != kDefined)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000163 return;
164
165 bool paren = false;
166 mLexer->lex(token);
167 if (token->type == '(')
168 {
169 paren = true;
170 mLexer->lex(token);
171 }
172
173 if (token->type != Token::IDENTIFIER)
174 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500175 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000176 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000177 skipUntilEOD(mLexer, token);
178 return;
179 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000180 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000181 std::string expression = iter != mMacroSet->end() ? "1" : "0";
182
183 if (paren)
184 {
185 mLexer->lex(token);
186 if (token->type != ')')
187 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500188 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000189 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000190 skipUntilEOD(mLexer, token);
191 return;
192 }
193 }
194
195 // We have a valid defined operator.
196 // Convert the current token into a CONST_INT token.
197 token->type = Token::CONST_INT;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000198 token->text = expression;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000199 }
200
201 private:
202 Lexer* mLexer;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000203 const MacroSet* mMacroSet;
204 Diagnostics* mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000205};
206
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000207DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000208 MacroSet* macroSet,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000209 Diagnostics* diagnostics,
210 DirectiveHandler* directiveHandler) :
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000211 mPastFirstStatement(false),
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000212 mTokenizer(tokenizer),
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000213 mMacroSet(macroSet),
alokp@chromium.org36124de82012-05-24 02:17:43 +0000214 mDiagnostics(diagnostics),
215 mDirectiveHandler(directiveHandler)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000216{
217}
218
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000219void DirectiveParser::lex(Token* token)
220{
221 do
222 {
223 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000224
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000225 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000226 {
227 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000228 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000229 }
230
231 if (token->type == Token::LAST)
232 {
233 if (!mConditionalStack.empty())
234 {
235 const ConditionalBlock& block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500236 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000237 block.location, block.type);
238 }
239 break;
240 }
241
242 } while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000243
244 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000245}
246
247void DirectiveParser::parseDirective(Token* token)
248{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000249 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000250
251 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000252 if (isEOD(token))
253 {
254 // Empty Directive.
255 return;
256 }
257
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000258 DirectiveType directive = getDirective(token);
259
260 // While in an excluded conditional block/group,
261 // we only parse conditional directives.
262 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000263 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000264 skipUntilEOD(mTokenizer, token);
265 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000266 }
267
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000268 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000269 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000270 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500271 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000272 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000273 skipUntilEOD(mTokenizer, token);
274 break;
275 case DIRECTIVE_DEFINE:
276 parseDefine(token);
277 break;
278 case DIRECTIVE_UNDEF:
279 parseUndef(token);
280 break;
281 case DIRECTIVE_IF:
282 parseIf(token);
283 break;
284 case DIRECTIVE_IFDEF:
285 parseIfdef(token);
286 break;
287 case DIRECTIVE_IFNDEF:
288 parseIfndef(token);
289 break;
290 case DIRECTIVE_ELSE:
291 parseElse(token);
292 break;
293 case DIRECTIVE_ELIF:
294 parseElif(token);
295 break;
296 case DIRECTIVE_ENDIF:
297 parseEndif(token);
298 break;
299 case DIRECTIVE_ERROR:
300 parseError(token);
301 break;
302 case DIRECTIVE_PRAGMA:
303 parsePragma(token);
304 break;
305 case DIRECTIVE_EXTENSION:
306 parseExtension(token);
307 break;
308 case DIRECTIVE_VERSION:
309 parseVersion(token);
310 break;
311 case DIRECTIVE_LINE:
312 parseLine(token);
313 break;
314 default:
315 assert(false);
316 break;
317 }
318
319 skipUntilEOD(mTokenizer, token);
320 if (token->type == Token::LAST)
321 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500322 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000323 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000324 }
325}
326
327void DirectiveParser::parseDefine(Token* token)
328{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000329 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000330
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000331 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000332 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000333 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500334 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000335 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000336 return;
337 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000338 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000339 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500340 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000341 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000342 return;
343 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000344 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000345 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500346 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000347 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000348 return;
349 }
350
351 Macro macro;
352 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000353 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000354
355 mTokenizer->lex(token);
356 if (token->type == '(' && !token->hasLeadingSpace())
357 {
358 // Function-like macro. Collect arguments.
359 macro.type = Macro::kTypeFunc;
360 do {
361 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000362 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000363 break;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000364 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000365
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000366 mTokenizer->lex(token); // Get ','.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000367 } while (token->type == ',');
368
369 if (token->type != ')')
370 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500371 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000372 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000373 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000374 return;
375 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000376 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000377 }
378
alokp@chromium.org7c884542012-05-24 19:13:03 +0000379 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000380 {
381 // Reset the token location because it is unnecessary in replacement
382 // list. Resetting it also allows us to reuse Token::equals() to
383 // compare macros.
384 token->location = SourceLocation();
385 macro.replacements.push_back(*token);
386 mTokenizer->lex(token);
387 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000388 if (!macro.replacements.empty())
389 {
390 // Whitespace preceding the replacement list is not considered part of
391 // the replacement list for either form of macro.
392 macro.replacements.front().setHasLeadingSpace(false);
393 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000394
395 // Check for macro redefinition.
396 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
397 if (iter != mMacroSet->end() && !macro.equals(iter->second))
398 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500399 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000400 token->location,
401 macro.name);
402 return;
403 }
404 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000405}
406
407void DirectiveParser::parseUndef(Token* token)
408{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000409 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000410
411 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000412 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000413 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500414 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000415 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000416 return;
417 }
418
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000419 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000420 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000421 {
422 if (iter->second.predefined)
423 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500424 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000425 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000426 }
427 else
428 {
429 mMacroSet->erase(iter);
430 }
431 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000432
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000433 mTokenizer->lex(token);
434}
435
436void DirectiveParser::parseIf(Token* token)
437{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000438 assert(getDirective(token) == DIRECTIVE_IF);
439 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000440}
441
442void DirectiveParser::parseIfdef(Token* token)
443{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000444 assert(getDirective(token) == DIRECTIVE_IFDEF);
445 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000446}
447
448void DirectiveParser::parseIfndef(Token* token)
449{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000450 assert(getDirective(token) == DIRECTIVE_IFNDEF);
451 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000452}
453
454void DirectiveParser::parseElse(Token* token)
455{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000456 assert(getDirective(token) == DIRECTIVE_ELSE);
457
458 if (mConditionalStack.empty())
459 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500460 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000461 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000462 skipUntilEOD(mTokenizer, token);
463 return;
464 }
465
466 ConditionalBlock& block = mConditionalStack.back();
467 if (block.skipBlock)
468 {
469 // No diagnostics. Just skip the whole line.
470 skipUntilEOD(mTokenizer, token);
471 return;
472 }
473 if (block.foundElseGroup)
474 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500475 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000476 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000477 skipUntilEOD(mTokenizer, token);
478 return;
479 }
480
481 block.foundElseGroup = true;
482 block.skipGroup = block.foundValidGroup;
483 block.foundValidGroup = true;
484
485 // Warn if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000486 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000487 if (!isEOD(token))
488 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500489 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000490 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000491 skipUntilEOD(mTokenizer, token);
492 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000493}
494
495void DirectiveParser::parseElif(Token* token)
496{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000497 assert(getDirective(token) == DIRECTIVE_ELIF);
498
499 if (mConditionalStack.empty())
500 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500501 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000502 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000503 skipUntilEOD(mTokenizer, token);
504 return;
505 }
506
507 ConditionalBlock& block = mConditionalStack.back();
508 if (block.skipBlock)
509 {
510 // No diagnostics. Just skip the whole line.
511 skipUntilEOD(mTokenizer, token);
512 return;
513 }
514 if (block.foundElseGroup)
515 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500516 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000517 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000518 skipUntilEOD(mTokenizer, token);
519 return;
520 }
521 if (block.foundValidGroup)
522 {
523 // Do not parse the expression.
524 // Also be careful not to emit a diagnostic.
525 block.skipGroup = true;
526 skipUntilEOD(mTokenizer, token);
527 return;
528 }
529
530 int expression = parseExpressionIf(token);
531 block.skipGroup = expression == 0;
532 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000533}
534
535void DirectiveParser::parseEndif(Token* token)
536{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000537 assert(getDirective(token) == DIRECTIVE_ENDIF);
538
539 if (mConditionalStack.empty())
540 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500541 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000542 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000543 skipUntilEOD(mTokenizer, token);
544 return;
545 }
546
547 mConditionalStack.pop_back();
548
549 // Warn if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000550 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000551 if (!isEOD(token))
552 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500553 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000554 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000555 skipUntilEOD(mTokenizer, token);
556 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000557}
558
559void DirectiveParser::parseError(Token* token)
560{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000561 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000562
alokp@chromium.org2e818912012-06-29 21:26:03 +0000563 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000564 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000565 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000566 {
567 stream << *token;
568 mTokenizer->lex(token);
569 }
570 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000571}
572
alokp@chromium.org36124de82012-05-24 02:17:43 +0000573// Parses pragma of form: #pragma name[(value)].
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000574void DirectiveParser::parsePragma(Token* token)
575{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000576 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000577
578 enum State
579 {
580 PRAGMA_NAME,
581 LEFT_PAREN,
582 PRAGMA_VALUE,
583 RIGHT_PAREN
584 };
585
586 bool valid = true;
587 std::string name, value;
588 int state = PRAGMA_NAME;
589
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000590 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000591 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000592 {
593 switch(state++)
594 {
595 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000596 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000597 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000598 break;
599 case LEFT_PAREN:
600 valid = valid && (token->type == '(');
601 break;
602 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000603 value = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000604 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000605 break;
606 case RIGHT_PAREN:
607 valid = valid && (token->type == ')');
608 break;
609 default:
610 valid = false;
611 break;
612 }
613 mTokenizer->lex(token);
614 }
615
616 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
617 (state == LEFT_PAREN) || // Without value.
618 (state == RIGHT_PAREN + 1)); // With value.
619 if (!valid)
620 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500621 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000622 token->location, name);
623 }
624 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
625 {
626 mDirectiveHandler->handlePragma(token->location, name, value);
627 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000628}
629
630void DirectiveParser::parseExtension(Token* token)
631{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000632 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000633
634 enum State
635 {
636 EXT_NAME,
637 COLON,
638 EXT_BEHAVIOR
639 };
640
641 bool valid = true;
642 std::string name, behavior;
643 int state = EXT_NAME;
644
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000645 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000646 while ((token->type != '\n') && (token->type != Token::LAST))
647 {
648 switch (state++)
649 {
650 case EXT_NAME:
651 if (valid && (token->type != Token::IDENTIFIER))
652 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500653 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000654 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000655 valid = false;
656 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000657 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000658 break;
659 case COLON:
660 if (valid && (token->type != ':'))
661 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500662 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000663 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000664 valid = false;
665 }
666 break;
667 case EXT_BEHAVIOR:
668 if (valid && (token->type != Token::IDENTIFIER))
669 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500670 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000671 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000672 valid = false;
673 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000674 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000675 break;
676 default:
677 if (valid)
678 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500679 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000680 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000681 valid = false;
682 }
683 break;
684 }
685 mTokenizer->lex(token);
686 }
687 if (valid && (state != EXT_BEHAVIOR + 1))
688 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500689 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000690 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000691 valid = false;
692 }
693 if (valid)
694 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000695}
696
697void DirectiveParser::parseVersion(Token* token)
698{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000699 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000700
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000701 if (mPastFirstStatement)
702 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500703 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000704 token->location, token->text);
705 skipUntilEOD(mTokenizer, token);
706 return;
707 }
708
alokp@chromium.org7c884542012-05-24 19:13:03 +0000709 enum State
710 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000711 VERSION_NUMBER,
712 VERSION_PROFILE,
713 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000714 };
715
716 bool valid = true;
717 int version = 0;
718 int state = VERSION_NUMBER;
719
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000720 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000721 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000722 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000723 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000724 {
725 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000726 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000727 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500728 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000729 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000730 valid = false;
731 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000732 if (valid && !token->iValue(&version))
733 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500734 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000735 token->location, token->text);
736 valid = false;
737 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000738 if (valid)
739 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000740 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
741 }
742 break;
743 case VERSION_PROFILE:
744 if (token->type != Token::IDENTIFIER || token->text != "es")
745 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500746 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000747 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000748 valid = false;
749 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000750 state = VERSION_ENDLINE;
751 break;
752 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500753 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000754 token->location, token->text);
755 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000756 break;
757 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000758
alokp@chromium.org7c884542012-05-24 19:13:03 +0000759 mTokenizer->lex(token);
760 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000761
762 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000763 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500764 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000765 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000766 valid = false;
767 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000768
alokp@chromium.org7c884542012-05-24 19:13:03 +0000769 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000770 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000771 mDirectiveHandler->handleVersion(token->location, version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000772 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000773}
774
775void DirectiveParser::parseLine(Token* token)
776{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000777 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000778
779 enum State
780 {
781 LINE_NUMBER,
782 FILE_NUMBER
783 };
784
785 bool valid = true;
786 int line = 0, file = 0;
787 int state = LINE_NUMBER;
788
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000789 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000790 macroExpander.lex(token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000791 while ((token->type != '\n') && (token->type != Token::LAST))
792 {
793 switch (state++)
794 {
795 case LINE_NUMBER:
796 if (valid && (token->type != Token::CONST_INT))
797 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500798 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000799 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000800 valid = false;
801 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000802 if (valid && !token->iValue(&line))
803 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500804 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000805 token->location, token->text);
806 valid = false;
807 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000808 break;
809 case FILE_NUMBER:
810 if (valid && (token->type != Token::CONST_INT))
811 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500812 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000813 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000814 valid = false;
815 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000816 if (valid && !token->iValue(&file))
817 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500818 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000819 token->location, token->text);
820 valid = false;
821 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000822 break;
823 default:
824 if (valid)
825 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500826 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000827 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000828 valid = false;
829 }
830 break;
831 }
832 macroExpander.lex(token);
833 }
834
835 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
836 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500837 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000838 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000839 valid = false;
840 }
841 if (valid)
842 {
843 mTokenizer->setLineNumber(line);
844 if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
845 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000846}
847
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000848bool DirectiveParser::skipping() const
849{
850 if (mConditionalStack.empty()) return false;
851
852 const ConditionalBlock& block = mConditionalStack.back();
853 return block.skipBlock || block.skipGroup;
854}
855
856void DirectiveParser::parseConditionalIf(Token* token)
857{
858 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000859 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000860 block.location = token->location;
861
862 if (skipping())
863 {
864 // This conditional block is inside another conditional group
865 // which is skipped. As a consequence this whole block is skipped.
866 // Be careful not to parse the conditional expression that might
867 // emit a diagnostic.
868 skipUntilEOD(mTokenizer, token);
869 block.skipBlock = true;
870 }
871 else
872 {
873 DirectiveType directive = getDirective(token);
874
875 int expression = 0;
876 switch (directive)
877 {
878 case DIRECTIVE_IF:
879 expression = parseExpressionIf(token);
880 break;
881 case DIRECTIVE_IFDEF:
882 expression = parseExpressionIfdef(token);
883 break;
884 case DIRECTIVE_IFNDEF:
885 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
886 break;
887 default:
888 assert(false);
889 break;
890 }
891 block.skipGroup = expression == 0;
892 block.foundValidGroup = expression != 0;
893 }
894 mConditionalStack.push_back(block);
895}
896
897int DirectiveParser::parseExpressionIf(Token* token)
898{
899 assert((getDirective(token) == DIRECTIVE_IF) ||
900 (getDirective(token) == DIRECTIVE_ELIF));
901
902 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
903 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
904 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
905
906 int expression = 0;
907 macroExpander.lex(token);
908 expressionParser.parse(token, &expression);
909
910 // Warn if there are tokens after #if expression.
911 if (!isEOD(token))
912 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500913 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000914 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000915 skipUntilEOD(mTokenizer, token);
916 }
917
918 return expression;
919}
920
921int DirectiveParser::parseExpressionIfdef(Token* token)
922{
923 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
924 (getDirective(token) == DIRECTIVE_IFNDEF));
925
926 mTokenizer->lex(token);
927 if (token->type != Token::IDENTIFIER)
928 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500929 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000930 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000931 skipUntilEOD(mTokenizer, token);
932 return 0;
933 }
934
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000935 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000936 int expression = iter != mMacroSet->end() ? 1 : 0;
937
938 // Warn if there are tokens after #ifdef expression.
939 mTokenizer->lex(token);
940 if (!isEOD(token))
941 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500942 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000943 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000944 skipUntilEOD(mTokenizer, token);
945 }
946 return expression;
947}
948
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000949} // namespace pp