blob: b38f33256f5b155e9c72a63fc169c107b6b95b90 [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
Geoff Lang26be18d2015-04-27 14:05:57 -04009#include <algorithm>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000010#include <cassert>
alokp@chromium.org51b96852012-05-30 20:25:05 +000011#include <cstdlib>
alokp@chromium.org36124de82012-05-24 02:17:43 +000012#include <sstream>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000013
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000014#include "DiagnosticsBase.h"
15#include "DirectiveHandlerBase.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000016#include "ExpressionParser.h"
17#include "MacroExpander.h"
18#include "Token.h"
19#include "Tokenizer.h"
20
21namespace {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000022enum DirectiveType
23{
24 DIRECTIVE_NONE,
25 DIRECTIVE_DEFINE,
26 DIRECTIVE_UNDEF,
27 DIRECTIVE_IF,
28 DIRECTIVE_IFDEF,
29 DIRECTIVE_IFNDEF,
30 DIRECTIVE_ELSE,
31 DIRECTIVE_ELIF,
32 DIRECTIVE_ENDIF,
33 DIRECTIVE_ERROR,
34 DIRECTIVE_PRAGMA,
35 DIRECTIVE_EXTENSION,
36 DIRECTIVE_VERSION,
37 DIRECTIVE_LINE
38};
alokp@chromium.org04d7d222012-05-16 19:24:07 +000039
Zhenyao Mod526f982014-05-13 14:51:19 -070040DirectiveType getDirective(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000041{
Zhenyao Mob5e17752014-10-22 10:57:10 -070042 const char kDirectiveDefine[] = "define";
43 const char kDirectiveUndef[] = "undef";
44 const char kDirectiveIf[] = "if";
45 const char kDirectiveIfdef[] = "ifdef";
46 const char kDirectiveIfndef[] = "ifndef";
47 const char kDirectiveElse[] = "else";
48 const char kDirectiveElif[] = "elif";
49 const char kDirectiveEndif[] = "endif";
50 const char kDirectiveError[] = "error";
51 const char kDirectivePragma[] = "pragma";
52 const char kDirectiveExtension[] = "extension";
53 const char kDirectiveVersion[] = "version";
54 const char kDirectiveLine[] = "line";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000055
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;
Zhenyao Mod526f982014-05-13 14:51:19 -070061 if (token->text == kDirectiveUndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000062 return DIRECTIVE_UNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070063 if (token->text == kDirectiveIf)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000064 return DIRECTIVE_IF;
Zhenyao Mod526f982014-05-13 14:51:19 -070065 if (token->text == kDirectiveIfdef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000066 return DIRECTIVE_IFDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070067 if (token->text == kDirectiveIfndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000068 return DIRECTIVE_IFNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070069 if (token->text == kDirectiveElse)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000070 return DIRECTIVE_ELSE;
Zhenyao Mod526f982014-05-13 14:51:19 -070071 if (token->text == kDirectiveElif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000072 return DIRECTIVE_ELIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070073 if (token->text == kDirectiveEndif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000074 return DIRECTIVE_ENDIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070075 if (token->text == kDirectiveError)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000076 return DIRECTIVE_ERROR;
Zhenyao Mod526f982014-05-13 14:51:19 -070077 if (token->text == kDirectivePragma)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000078 return DIRECTIVE_PRAGMA;
Zhenyao Mod526f982014-05-13 14:51:19 -070079 if (token->text == kDirectiveExtension)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000080 return DIRECTIVE_EXTENSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070081 if (token->text == kDirectiveVersion)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000082 return DIRECTIVE_VERSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070083 if (token->text == kDirectiveLine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000084 return DIRECTIVE_LINE;
85
86 return DIRECTIVE_NONE;
87}
88
Zhenyao Mod526f982014-05-13 14:51:19 -070089bool isConditionalDirective(DirectiveType directive)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000090{
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.
Zhenyao Mod526f982014-05-13 14:51:19 -0700106bool isEOD(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000107{
108 return (token->type == '\n') || (token->type == pp::Token::LAST);
109}
110
Zhenyao Mod526f982014-05-13 14:51:19 -0700111void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000112{
113 while(!isEOD(token))
114 {
115 lexer->lex(token);
116 }
117}
118
Zhenyao Mod526f982014-05-13 14:51:19 -0700119bool isMacroNameReserved(const std::string &name)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000120{
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
Zhenyao Mod526f982014-05-13 14:51:19 -0700132bool isMacroPredefined(const std::string &name,
133 const pp::MacroSet &macroSet)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000134{
135 pp::MacroSet::const_iterator iter = macroSet.find(name);
136 return iter != macroSet.end() ? iter->second.predefined : false;
137}
138
Zhenyao Mod526f982014-05-13 14:51:19 -0700139} // namespace anonymous
140
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000141namespace pp
142{
143
144class DefinedParser : public Lexer
145{
146 public:
Zhenyao Mod526f982014-05-13 14:51:19 -0700147 DefinedParser(Lexer *lexer,
148 const MacroSet *macroSet,
149 Diagnostics *diagnostics)
150 : mLexer(lexer),
151 mMacroSet(macroSet),
152 mDiagnostics(diagnostics)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000153 {
154 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000155
156 protected:
Zhenyao Mod526f982014-05-13 14:51:19 -0700157 virtual void lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000158 {
Zhenyao Mob5e17752014-10-22 10:57:10 -0700159 const char kDefined[] = "defined";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000160
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000161 mLexer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000162 if (token->type != Token::IDENTIFIER)
163 return;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000164 if (token->text != kDefined)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000165 return;
166
167 bool paren = false;
168 mLexer->lex(token);
169 if (token->type == '(')
170 {
171 paren = true;
172 mLexer->lex(token);
173 }
174
175 if (token->type != Token::IDENTIFIER)
176 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500177 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000178 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000179 skipUntilEOD(mLexer, token);
180 return;
181 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000182 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000183 std::string expression = iter != mMacroSet->end() ? "1" : "0";
184
185 if (paren)
186 {
187 mLexer->lex(token);
188 if (token->type != ')')
189 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500190 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000191 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000192 skipUntilEOD(mLexer, token);
193 return;
194 }
195 }
196
197 // We have a valid defined operator.
198 // Convert the current token into a CONST_INT token.
199 token->type = Token::CONST_INT;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000200 token->text = expression;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000201 }
202
203 private:
Zhenyao Mod526f982014-05-13 14:51:19 -0700204 Lexer *mLexer;
205 const MacroSet *mMacroSet;
206 Diagnostics *mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000207};
208
Zhenyao Mod526f982014-05-13 14:51:19 -0700209DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
210 MacroSet *macroSet,
211 Diagnostics *diagnostics,
212 DirectiveHandler *directiveHandler)
213 : mPastFirstStatement(false),
214 mTokenizer(tokenizer),
215 mMacroSet(macroSet),
216 mDiagnostics(diagnostics),
217 mDirectiveHandler(directiveHandler)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000218{
219}
220
Zhenyao Mod526f982014-05-13 14:51:19 -0700221void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000222{
223 do
224 {
225 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000226
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000227 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000228 {
229 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000230 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000231 }
232
233 if (token->type == Token::LAST)
234 {
235 if (!mConditionalStack.empty())
236 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700237 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500238 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000239 block.location, block.type);
240 }
241 break;
242 }
243
Zhenyao Mod526f982014-05-13 14:51:19 -0700244 }
245 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000246
247 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000248}
249
Zhenyao Mod526f982014-05-13 14:51:19 -0700250void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000251{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000252 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000253
254 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000255 if (isEOD(token))
256 {
257 // Empty Directive.
258 return;
259 }
260
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000261 DirectiveType directive = getDirective(token);
262
263 // While in an excluded conditional block/group,
264 // we only parse conditional directives.
265 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000266 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000267 skipUntilEOD(mTokenizer, token);
268 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000269 }
270
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000271 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000272 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000273 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500274 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000275 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000276 skipUntilEOD(mTokenizer, token);
277 break;
278 case DIRECTIVE_DEFINE:
279 parseDefine(token);
280 break;
281 case DIRECTIVE_UNDEF:
282 parseUndef(token);
283 break;
284 case DIRECTIVE_IF:
285 parseIf(token);
286 break;
287 case DIRECTIVE_IFDEF:
288 parseIfdef(token);
289 break;
290 case DIRECTIVE_IFNDEF:
291 parseIfndef(token);
292 break;
293 case DIRECTIVE_ELSE:
294 parseElse(token);
295 break;
296 case DIRECTIVE_ELIF:
297 parseElif(token);
298 break;
299 case DIRECTIVE_ENDIF:
300 parseEndif(token);
301 break;
302 case DIRECTIVE_ERROR:
303 parseError(token);
304 break;
305 case DIRECTIVE_PRAGMA:
306 parsePragma(token);
307 break;
308 case DIRECTIVE_EXTENSION:
309 parseExtension(token);
310 break;
311 case DIRECTIVE_VERSION:
312 parseVersion(token);
313 break;
314 case DIRECTIVE_LINE:
315 parseLine(token);
316 break;
317 default:
318 assert(false);
319 break;
320 }
321
322 skipUntilEOD(mTokenizer, token);
323 if (token->type == Token::LAST)
324 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500325 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000326 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000327 }
328}
329
Zhenyao Mod526f982014-05-13 14:51:19 -0700330void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000331{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000332 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000333
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000334 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000335 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000336 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500337 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000338 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000339 return;
340 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000341 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000342 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500343 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000344 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000345 return;
346 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000347 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000348 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500349 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000350 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000351 return;
352 }
353
354 Macro macro;
355 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000356 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000357
358 mTokenizer->lex(token);
359 if (token->type == '(' && !token->hasLeadingSpace())
360 {
361 // Function-like macro. Collect arguments.
362 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700363 do
364 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000365 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000366 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000367 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400368
369 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
370 {
371 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
372 token->location, token->text);
373 return;
374 }
375
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000376 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000377
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000378 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700379 }
380 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000381
382 if (token->type != ')')
383 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500384 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000385 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000386 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000387 return;
388 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000389 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000390 }
391
alokp@chromium.org7c884542012-05-24 19:13:03 +0000392 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000393 {
394 // Reset the token location because it is unnecessary in replacement
395 // list. Resetting it also allows us to reuse Token::equals() to
396 // compare macros.
397 token->location = SourceLocation();
398 macro.replacements.push_back(*token);
399 mTokenizer->lex(token);
400 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000401 if (!macro.replacements.empty())
402 {
403 // Whitespace preceding the replacement list is not considered part of
404 // the replacement list for either form of macro.
405 macro.replacements.front().setHasLeadingSpace(false);
406 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000407
408 // Check for macro redefinition.
409 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
410 if (iter != mMacroSet->end() && !macro.equals(iter->second))
411 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500412 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000413 token->location,
414 macro.name);
415 return;
416 }
417 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000418}
419
Zhenyao Mod526f982014-05-13 14:51:19 -0700420void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000421{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000422 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000423
424 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000425 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000426 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500427 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000428 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000429 return;
430 }
431
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000432 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000433 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000434 {
435 if (iter->second.predefined)
436 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500437 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000438 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000439 }
440 else
441 {
442 mMacroSet->erase(iter);
443 }
444 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000445
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000446 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400447 if (!isEOD(token))
448 {
449 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
450 token->location, token->text);
451 skipUntilEOD(mTokenizer, token);
452 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000453}
454
Zhenyao Mod526f982014-05-13 14:51:19 -0700455void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000456{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000457 assert(getDirective(token) == DIRECTIVE_IF);
458 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000459}
460
Zhenyao Mod526f982014-05-13 14:51:19 -0700461void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000462{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000463 assert(getDirective(token) == DIRECTIVE_IFDEF);
464 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000465}
466
Zhenyao Mod526f982014-05-13 14:51:19 -0700467void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000468{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000469 assert(getDirective(token) == DIRECTIVE_IFNDEF);
470 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471}
472
Zhenyao Mod526f982014-05-13 14:51:19 -0700473void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000475 assert(getDirective(token) == DIRECTIVE_ELSE);
476
477 if (mConditionalStack.empty())
478 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500479 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000480 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000481 skipUntilEOD(mTokenizer, token);
482 return;
483 }
484
Zhenyao Mod526f982014-05-13 14:51:19 -0700485 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000486 if (block.skipBlock)
487 {
488 // No diagnostics. Just skip the whole line.
489 skipUntilEOD(mTokenizer, token);
490 return;
491 }
492 if (block.foundElseGroup)
493 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500494 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000495 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000496 skipUntilEOD(mTokenizer, token);
497 return;
498 }
499
500 block.foundElseGroup = true;
501 block.skipGroup = block.foundValidGroup;
502 block.foundValidGroup = true;
503
Geoff Lang95a423d2015-04-28 11:09:45 -0400504 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000505 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000506 if (!isEOD(token))
507 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500508 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000509 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000510 skipUntilEOD(mTokenizer, token);
511 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000512}
513
Zhenyao Mod526f982014-05-13 14:51:19 -0700514void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000515{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000516 assert(getDirective(token) == DIRECTIVE_ELIF);
517
518 if (mConditionalStack.empty())
519 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500520 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000521 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000522 skipUntilEOD(mTokenizer, token);
523 return;
524 }
525
Zhenyao Mod526f982014-05-13 14:51:19 -0700526 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000527 if (block.skipBlock)
528 {
529 // No diagnostics. Just skip the whole line.
530 skipUntilEOD(mTokenizer, token);
531 return;
532 }
533 if (block.foundElseGroup)
534 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500535 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000536 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000537 skipUntilEOD(mTokenizer, token);
538 return;
539 }
540 if (block.foundValidGroup)
541 {
542 // Do not parse the expression.
543 // Also be careful not to emit a diagnostic.
544 block.skipGroup = true;
545 skipUntilEOD(mTokenizer, token);
546 return;
547 }
548
549 int expression = parseExpressionIf(token);
550 block.skipGroup = expression == 0;
551 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000552}
553
Zhenyao Mod526f982014-05-13 14:51:19 -0700554void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000555{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000556 assert(getDirective(token) == DIRECTIVE_ENDIF);
557
558 if (mConditionalStack.empty())
559 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500560 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000561 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000562 skipUntilEOD(mTokenizer, token);
563 return;
564 }
565
566 mConditionalStack.pop_back();
567
Geoff Lang95a423d2015-04-28 11:09:45 -0400568 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000569 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000570 if (!isEOD(token))
571 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500572 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000573 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000574 skipUntilEOD(mTokenizer, token);
575 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000576}
577
Zhenyao Mod526f982014-05-13 14:51:19 -0700578void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000579{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000580 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000581
alokp@chromium.org2e818912012-06-29 21:26:03 +0000582 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000583 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000584 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000585 {
586 stream << *token;
587 mTokenizer->lex(token);
588 }
589 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000590}
591
alokp@chromium.org36124de82012-05-24 02:17:43 +0000592// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700593void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000594{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000595 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000596
597 enum State
598 {
599 PRAGMA_NAME,
600 LEFT_PAREN,
601 PRAGMA_VALUE,
602 RIGHT_PAREN
603 };
604
605 bool valid = true;
606 std::string name, value;
607 int state = PRAGMA_NAME;
608
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000609 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700610 bool stdgl = token->text == "STDGL";
611 if (stdgl)
612 {
613 mTokenizer->lex(token);
614 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000615 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000616 {
617 switch(state++)
618 {
619 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000620 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000621 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000622 break;
623 case LEFT_PAREN:
624 valid = valid && (token->type == '(');
625 break;
626 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000627 value = token->text;
Geoff Langd3c29f52015-04-28 11:23:02 -0400628 // Pragma value validation is handled in DirectiveHandler::handlePragma
629 // because the proper pragma value is dependent on the pragma name.
alokp@chromium.org36124de82012-05-24 02:17:43 +0000630 break;
631 case RIGHT_PAREN:
632 valid = valid && (token->type == ')');
633 break;
634 default:
635 valid = false;
636 break;
637 }
638 mTokenizer->lex(token);
639 }
640
641 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
642 (state == LEFT_PAREN) || // Without value.
643 (state == RIGHT_PAREN + 1)); // With value.
644 if (!valid)
645 {
Geoff Langd3c29f52015-04-28 11:23:02 -0400646 mDiagnostics->report(Diagnostics::PP_INVALID_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000647 token->location, name);
648 }
649 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
650 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700651 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000652 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000653}
654
Zhenyao Mod526f982014-05-13 14:51:19 -0700655void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000656{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000657 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000658
659 enum State
660 {
661 EXT_NAME,
662 COLON,
663 EXT_BEHAVIOR
664 };
665
666 bool valid = true;
667 std::string name, behavior;
668 int state = EXT_NAME;
669
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000670 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000671 while ((token->type != '\n') && (token->type != Token::LAST))
672 {
673 switch (state++)
674 {
675 case EXT_NAME:
676 if (valid && (token->type != Token::IDENTIFIER))
677 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500678 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000679 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000680 valid = false;
681 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000682 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000683 break;
684 case COLON:
685 if (valid && (token->type != ':'))
686 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500687 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000688 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000689 valid = false;
690 }
691 break;
692 case EXT_BEHAVIOR:
693 if (valid && (token->type != Token::IDENTIFIER))
694 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500695 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000696 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000697 valid = false;
698 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000699 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000700 break;
701 default:
702 if (valid)
703 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500704 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000705 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000706 valid = false;
707 }
708 break;
709 }
710 mTokenizer->lex(token);
711 }
712 if (valid && (state != EXT_BEHAVIOR + 1))
713 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500714 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000715 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000716 valid = false;
717 }
718 if (valid)
719 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000720}
721
Zhenyao Mod526f982014-05-13 14:51:19 -0700722void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000723{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000724 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000725
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000726 if (mPastFirstStatement)
727 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500728 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000729 token->location, token->text);
730 skipUntilEOD(mTokenizer, token);
731 return;
732 }
733
alokp@chromium.org7c884542012-05-24 19:13:03 +0000734 enum State
735 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000736 VERSION_NUMBER,
737 VERSION_PROFILE,
738 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000739 };
740
741 bool valid = true;
742 int version = 0;
743 int state = VERSION_NUMBER;
744
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000745 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000746 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000747 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000748 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000749 {
750 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000751 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000752 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500753 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000754 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000755 valid = false;
756 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000757 if (valid && !token->iValue(&version))
758 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500759 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000760 token->location, token->text);
761 valid = false;
762 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000763 if (valid)
764 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000765 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
766 }
767 break;
768 case VERSION_PROFILE:
769 if (token->type != Token::IDENTIFIER || token->text != "es")
770 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500771 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000772 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000773 valid = false;
774 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000775 state = VERSION_ENDLINE;
776 break;
777 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500778 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000779 token->location, token->text);
780 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000781 break;
782 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000783
alokp@chromium.org7c884542012-05-24 19:13:03 +0000784 mTokenizer->lex(token);
785 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000786
787 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000788 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500789 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000790 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000791 valid = false;
792 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000793
alokp@chromium.org7c884542012-05-24 19:13:03 +0000794 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000795 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000796 mDirectiveHandler->handleVersion(token->location, version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000797 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000798}
799
Zhenyao Mod526f982014-05-13 14:51:19 -0700800void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000801{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000802 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000803
804 enum State
805 {
806 LINE_NUMBER,
807 FILE_NUMBER
808 };
809
810 bool valid = true;
811 int line = 0, file = 0;
812 int state = LINE_NUMBER;
813
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000814 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000815 macroExpander.lex(token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000816 while ((token->type != '\n') && (token->type != Token::LAST))
817 {
818 switch (state++)
819 {
820 case LINE_NUMBER:
821 if (valid && (token->type != Token::CONST_INT))
822 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500823 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000824 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000825 valid = false;
826 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000827 if (valid && !token->iValue(&line))
828 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500829 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000830 token->location, token->text);
831 valid = false;
832 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000833 break;
834 case FILE_NUMBER:
835 if (valid && (token->type != Token::CONST_INT))
836 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500837 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
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 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000841 if (valid && !token->iValue(&file))
842 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500843 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000844 token->location, token->text);
845 valid = false;
846 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000847 break;
848 default:
849 if (valid)
850 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500851 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000852 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000853 valid = false;
854 }
855 break;
856 }
857 macroExpander.lex(token);
858 }
859
860 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
861 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500862 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000863 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000864 valid = false;
865 }
866 if (valid)
867 {
868 mTokenizer->setLineNumber(line);
Zhenyao Mod526f982014-05-13 14:51:19 -0700869 if (state == FILE_NUMBER + 1)
870 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000871 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000872}
873
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000874bool DirectiveParser::skipping() const
875{
Zhenyao Mod526f982014-05-13 14:51:19 -0700876 if (mConditionalStack.empty())
877 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000878
879 const ConditionalBlock& block = mConditionalStack.back();
880 return block.skipBlock || block.skipGroup;
881}
882
Zhenyao Mod526f982014-05-13 14:51:19 -0700883void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000884{
885 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000886 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000887 block.location = token->location;
888
889 if (skipping())
890 {
891 // This conditional block is inside another conditional group
892 // which is skipped. As a consequence this whole block is skipped.
893 // Be careful not to parse the conditional expression that might
894 // emit a diagnostic.
895 skipUntilEOD(mTokenizer, token);
896 block.skipBlock = true;
897 }
898 else
899 {
900 DirectiveType directive = getDirective(token);
901
902 int expression = 0;
903 switch (directive)
904 {
905 case DIRECTIVE_IF:
906 expression = parseExpressionIf(token);
907 break;
908 case DIRECTIVE_IFDEF:
909 expression = parseExpressionIfdef(token);
910 break;
911 case DIRECTIVE_IFNDEF:
912 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
913 break;
914 default:
915 assert(false);
916 break;
917 }
918 block.skipGroup = expression == 0;
919 block.foundValidGroup = expression != 0;
920 }
921 mConditionalStack.push_back(block);
922}
923
Zhenyao Mod526f982014-05-13 14:51:19 -0700924int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000925{
926 assert((getDirective(token) == DIRECTIVE_IF) ||
927 (getDirective(token) == DIRECTIVE_ELIF));
928
929 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
930 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
931 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
932
933 int expression = 0;
934 macroExpander.lex(token);
935 expressionParser.parse(token, &expression);
936
Geoff Lang95a423d2015-04-28 11:09:45 -0400937 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000938 if (!isEOD(token))
939 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500940 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000941 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000942 skipUntilEOD(mTokenizer, token);
943 }
944
945 return expression;
946}
947
Zhenyao Mod526f982014-05-13 14:51:19 -0700948int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000949{
950 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
951 (getDirective(token) == DIRECTIVE_IFNDEF));
952
953 mTokenizer->lex(token);
954 if (token->type != Token::IDENTIFIER)
955 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500956 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000957 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000958 skipUntilEOD(mTokenizer, token);
959 return 0;
960 }
961
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000962 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000963 int expression = iter != mMacroSet->end() ? 1 : 0;
964
Geoff Lang95a423d2015-04-28 11:09:45 -0400965 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000966 mTokenizer->lex(token);
967 if (!isEOD(token))
968 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500969 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000970 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000971 skipUntilEOD(mTokenizer, token);
972 }
973 return expression;
974}
975
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000976} // namespace pp